In redis.conf, 1g and 1gb are different numbers
30 July 2026
There is a tool for this on the siteRedis accepts both of these and they do not mean the same thing:
maxmemory 1g
maxmemory 1gb
1g is one billion bytes. 1gb is 2³⁰, which is 1,073,741,824. The difference
is about 7%, and the version without the b is the smaller one.
The rule
From the comment in Redis’s own default configuration file:
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
A bare suffix is decimal. A suffix with b is binary.
This is the opposite of the convention almost everywhere else, where GB is the
ambiguous decimal one and GiB is the explicit binary one. Redis uses neither
notation, and its shorter form is the decimal one, which is the direction nobody
guesses.
The units are case-insensitive, so 1GB and 1gb are identical. It is the
presence of the b that decides, not the capitalisation, which means a config
written in a house style of uppercase units is unaffected and one written
tersely is not.
Why the smaller number is the dangerous direction
If you meant 1 GiB and wrote 1g, Redis is now capped 73 megabytes below what
the capacity plan assumed. On a 1 GB instance that is 7% of the budget gone
before any data is written.
Nothing fails at startup. Nothing appears in the logs. CONFIG GET maxmemory
returns bytes, so it will tell you the truth if you ask, and nobody asks.
The instance runs normally until it reaches the cap, at which point the eviction
policy engages earlier than modelled. The symptom is a hit rate a few points
below projection with no obvious cause, or on noeviction, write errors at a
memory figure that does not match the configured one.
Seven percent is small enough to be attributed to almost anything: a traffic change, a new feature, a bigger average value. It is rarely attributed to the config.
It is not just maxmemory
Every size in redis.conf goes through the same parser:
| Setting | What a 7% error does |
|---|---|
maxmemory | Eviction starts early, or writes fail early |
client-output-buffer-limit | Replicas and pub/sub subscribers disconnect under load sooner than sized |
repl-backlog-size | A shorter disconnect window before a partial resync becomes a full one |
proto-max-bulk-len | A slightly smaller maximum value size |
client-output-buffer-limit is the one to look at twice, because it takes
two sizes on one line, a hard limit and a soft limit:
client-output-buffer-limit replica 256mb 64mb 60
Getting either 7% smaller than intended means replica disconnections under load you have already sized against, and a replica that disconnects triggers a resync, which increases load, which makes the next disconnect more likely. It is the one place where this small error has a feedback loop attached.
repl-backlog-size matters for the same reason: too small and a brief network
blip turns a cheap partial resynchronisation into a full RDB transfer.
The wrong instinct: convert everything to bytes
The obvious fix is to write raw byte counts and remove the ambiguity. It works
and it is worse to read: 1073741824 in a config file tells the next person
nothing and invites a typo that is invisible.
Write the b. maxmemory 1gb is unambiguous, is almost always what was
meant, and reads correctly. If you genuinely want decimal, that is the case for
writing it out in bytes with a comment saying why, because a bare 1g will be
“corrected” to 1gb by the next person who reads this article.
The bigger error next door: overhead is not payload
Worth raising alongside, because a team that has just fixed a 7% unit error is usually still carrying a much larger sizing error.
maxmemory bounds what Redis reports as used_memory, and that is not the
size of your values.
Per-key overhead. Every key carries a robj header, a dictionary entry, and
the key string itself. For small values this dominates: ten million keys holding
100-byte strings is nowhere near 1 GB.
Allocator rounding. jemalloc rounds each allocation up to a size class, so a 33-byte string does not occupy 33 bytes. The rounding is bounded but not small in aggregate.
Encoding cliffs. Small collections are stored in a compact listpack encoding
until they cross a threshold (hash-max-listpack-entries,
hash-max-listpack-value and their list, set and zset equivalents), at which
point the representation switches to a hashtable or skiplist and memory per
element jumps discontinuously. One extra field on a hash can move it across
that line and multiply its footprint.
That last one is why linear capacity projections fail. “We have ten million keys averaging 100 bytes, so we need a gigabyte” is wrong by a factor that depends on your key lengths and your encoding thresholds, and the error is not a constant you can multiply in.
Two things to check on a live instance:
> INFO memory
used_memory:2147483648
used_memory_rss:2952790016
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:1.37
> MEMORY USAGE mykey
(integer) 168
MEMORY USAGE on a representative sample of real keys, multiplied out, beats
any estimate from value sizes. It is the closest thing to a measurement
available without a full dump.
What changed recently
listpack replaced ziplist as the compact encoding for hashes, lists and
zsets in Redis 7.0, and the config names changed with it:
hash-max-ziplist-entries became hash-max-listpack-entries. The old names are
still accepted as aliases, so a config carried forward works and does not
signal that the newer tuning knobs exist.
Sets got a listpack encoding too in 7.2, via set-max-listpack-entries.
Small sets of non-integer values used to jump straight to a hashtable and now do
not, which changes the memory profile of anything using many small sets.
Redis 8 folded several modules into the core, which shifts the baseline
used_memory on a fresh instance. Not large, and worth re-baselining rather
than reusing a number from an older version.
Sizing an instance properly
1. Fix the units first. Grep the config for a size without a b and decide
whether it was intended.
2. Measure, do not estimate. Load a realistic sample, read used_memory,
divide by the key count. Ten thousand real keys tells you more than any
calculation.
3. Check where your collections sit relative to the encoding thresholds. If a typical hash has 120 fields and the threshold is 128, you are one product change away from a step increase across the whole keyspace.
4. Leave headroom for fragmentation. mem_fragmentation_ratio above about
1.5 means the process is holding substantially more RSS than Redis is using.
Below 1.0 means the opposite and is worse: the instance is swapping, which for a
single-threaded in-memory store is close to an outage.
5. Set maxmemory below the container limit, not equal to it. Redis
enforces its own cap against used_memory, and the kernel enforces the
container limit against RSS. If those are the same number, fragmentation alone
gets you OOM-killed while Redis believes it has room.
When the units do not matter
If you set maxmemory in bytes or with an explicit b, this is already a
non-issue and the rest of the sizing advice is the useful part.
If you are not running with a maxmemory at all, which is the default, the
unit question is moot and you have a different problem: an instance with no cap
will grow until the kernel intervenes, and the OOM killer is a worse eviction
policy than any of Redis’s.
On a dedicated host with generous headroom, 7% may be genuinely irrelevant. The reason to fix it anyway is that the next person to read the config will assume binary, and the gap between what is written and what is meant is the part that eventually costs something.
The short version
- Bare suffix is decimal, suffix with
bis binary.1g<1gb, by 7%. - Case does not matter. The
bdoes. - It applies to every size in
redis.conf, including the two-valueclient-output-buffer-limit. - No error, no log line.
CONFIG GETreturns bytes and will tell you. - The bigger sizing error is usually overhead: per-key structures, jemalloc rounding, and encoding cliffs that are step functions rather than slopes.
- Measure with
MEMORY USAGEon real keys. Do not project from value sizes. - Set
maxmemorybelow the container limit, because they measure different things.
The Redis memory calculator models per-key overhead, jemalloc size classes and the encoding thresholds, and reports the element count at which a collection changes representation, which is the cliff that turns a linear projection into a wrong one.