Kubernetes
resource management
M vs Mi
documentation
cloud computing

What are the difference between M and Mi in Kubernetes resources documentation?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Kubernetes resource specifications, M and Mi are different memory units that represent different byte counts. M (megabyte) is a decimal unit equal to 1,000,000 bytes, while Mi (mebibyte) is a binary unit equal to 1,048,576 bytes. They are not interchangeable: Mi is roughly 4.86% larger than M for the same numeric value. On top of that, lowercase m in CPU specifications means "millicpu" (thousandths of a CPU core), which is a completely different concept. Getting any of these mixed up leads to misconfigured resource requests and limits.

Decimal vs. Binary Units

Kubernetes follows the standard quantity notation that distinguishes between powers of 10 (SI/decimal) and powers of 2 (IEC/binary):

SuffixNameBaseBytes
KKilobyte10^31,000
KiKibibyte2^101,024
MMegabyte10^61,000,000
MiMebibyte2^201,048,576
GGigabyte10^91,000,000,000
GiGibibyte2^301,073,741,824
TTerabyte10^121,000,000,000,000
TiTebibyte2^401,099,511,627,776

The "i" stands for "binary" (from the IEC standard naming). The difference grows with scale:

plaintext
11M  = 1,000,000 bytes
21Mi = 1,048,576 bytes     (4.86% more)
3
41G  = 1,000,000,000 bytes
51Gi = 1,073,741,824 bytes (7.37% more)

At the gigabyte level, the gap is over 73 MB. For a cluster running hundreds of pods, this discrepancy adds up.

CPU Units: The Lowercase m Trap

The most common confusion comes from lowercase m in CPU specifications. In the CPU context, m stands for "millicpu" (one-thousandth of a CPU core), not "mega" or "megabyte":

yaml
1resources:
2  requests:
3    cpu: "500m"      # 0.5 CPU cores (millicpu)
4    memory: "512Mi"  # 512 mebibytes
5  limits:
6    cpu: "1"         # 1 full CPU core
7    memory: "1Gi"    # 1 gibibyte

Quick reference:

NotationResourceMeaning
500mCPUHalf a CPU core (500 millicpu)
500MMemory500,000,000 bytes (500 megabytes)
500MiMemory524,288,000 bytes (500 mebibytes)

These three look similar but represent entirely different quantities. Accidentally writing memory: "500m" would request 0.5 bytes of memory, which is nonsensical but syntactically valid in Kubernetes.

Real-World Manifest Examples

Standard Web Application

yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: web-api
5spec:
6  template:
7    spec:
8      containers:
9        - name: api
10          image: myapp:latest
11          resources:
12            requests:
13              cpu: "250m"
14              memory: "256Mi"
15            limits:
16              cpu: "1"
17              memory: "512Mi"

Memory-Intensive Data Processing

yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4  name: data-processor
5spec:
6  template:
7    spec:
8      containers:
9        - name: processor
10          image: processor:latest
11          resources:
12            requests:
13              cpu: "2"
14              memory: "4Gi"
15            limits:
16              cpu: "4"
17              memory: "8Gi"

Sidecar Container

yaml
1- name: log-forwarder
2  image: fluentbit:latest
3  resources:
4    requests:
5      cpu: "50m"
6      memory: "64Mi"
7    limits:
8      cpu: "100m"
9      memory: "128Mi"

Why the Difference Matters Operationally

Scheduling and Bin Packing

The Kubernetes scheduler uses resource requests to decide which node can fit a pod. If you accidentally use M when you meant Mi (or vice versa), each pod requests a slightly different amount than intended. Across a fleet:

plaintext
1100 pods x 512Mi = 53,687,091,200 bytes total
2100 pods x 512M  = 51,200,000,000 bytes total
3
4Difference: ~2.4 GB

That 2.4 GB gap can mean the difference between fitting one more pod on a node or triggering a scale-up event.

OOM Kill Behavior

Memory limits are enforced by the Linux kernel via cgroups. If you set a limit of 1G (1,000,000,000 bytes) but your application expects 1Gi (1,073,741,824 bytes) of headroom, the process may get OOM-killed when it uses more than 1 GB but less than 1 GiB.

Monitoring Confusion

Most monitoring tools (Prometheus, Grafana, kubectl top) report memory in binary units. If your manifests use decimal units but your dashboards show binary values, the numbers will not match, creating confusion during incident response.

Inspecting Current Resource Usage

You can check what your pods actually use vs. what they request:

bash
1# Current usage
2kubectl top pods -n default
3
4# Requested and limit values from the spec
5kubectl get pods -n default -o custom-columns=\
6"NAME:.metadata.name,\
7REQ_CPU:.spec.containers[0].resources.requests.cpu,\
8REQ_MEM:.spec.containers[0].resources.requests.memory,\
9LIM_CPU:.spec.containers[0].resources.limits.cpu,\
10LIM_MEM:.spec.containers[0].resources.limits.memory"

Validating Unit Consistency with OPA or Kyverno

For teams managing many manifests, policy engines can enforce consistent unit usage:

yaml
1# Kyverno policy to require binary memory units
2apiVersion: kyverno.io/v1
3kind: ClusterPolicy
4metadata:
5  name: require-binary-memory-units
6spec:
7  rules:
8    - name: check-memory-units
9      match:
10        resources:
11          kinds:
12            - Pod
13      validate:
14        message: "Memory values must use binary units (Mi, Gi)"
15        pattern:
16          spec:
17            containers:
18              - resources:
19                  requests:
20                    memory: "*i"
21                  limits:
22                    memory: "*i"

A simple convention that eliminates confusion:

  • Always use binary units for memory: Mi, Gi.
  • Always use m (millicpu) for fractional CPU: 250m, 500m, 1000m.
  • Use whole numbers for full cores: 1, 2, 4.
  • Document the convention in a shared Helm values template or a policy as code rule.

This matches how operating systems report memory (in binary) and avoids any mismatch between what you specify and what monitoring tools report.

Common Pitfalls

  • Treating M and Mi as interchangeable. They differ by nearly 5% at the megabyte level and over 7% at the gigabyte level. This affects scheduling, OOM thresholds, and cost.
  • Confusing uppercase M (memory megabytes) with lowercase m (CPU millicores). 500M of memory and 500m of CPU are completely different things.
  • Mixing decimal and binary units across manifests within the same project. Inconsistency makes code reviews error-prone and monitoring confusing.
  • Assuming Kubernetes normalizes units to match your intent. Kubernetes stores and enforces exactly what you write. 512M and 512Mi result in different cgroup limits.
  • Forgetting that e notation is also valid. 128974848 (plain bytes) and 129e6 are valid memory values, but they make manifests harder to read and review.

Summary

  • M is decimal megabytes (1,000,000 bytes) and Mi is binary mebibytes (1,048,576 bytes). They are not interchangeable.
  • Lowercase m is a CPU unit meaning millicpu (1/1000 of a core), completely unrelated to memory.
  • The percentage gap between decimal and binary grows with scale and affects scheduling, OOM behavior, and monitoring.
  • Standardize on binary units (Mi, Gi) for memory to match OS-level reporting.
  • Use policy engines like Kyverno or OPA to enforce unit conventions across your cluster.

Course illustration
Course illustration

All Rights Reserved.