INFO memory field-by-field, MEMORY USAGE and MEMORY DOCTOR, scanning for oversized keys, encoding threshold tuning, active defragmentation configuration, and a production workflow for diagnosing unexpected memory growth.
P-4 — Memory Profiling and Optimization
Who this module is for: Redis is using more RAM than expected and you do not know why. Or you are designing a Redis schema and want to estimate memory costs before deploying. This module covers the full suite of Redis memory inspection tools and the optimizations that consistently recover the most RAM in production.
The Memory Audit Starting Point: INFO memory
Every Redis memory investigation starts here:
INFO memory
used_memory: 1528000000 → allocations from Redis's perspective (bytes)
used_memory_human: 1.42G
used_memory_rss: 2097152000 → RSS reported by OS (includes fragmentation)
used_memory_rss_human: 1.95G
used_memory_peak: 1600000000 → peak allocation since server start
used_memory_peak_human: 1.49G
used_memory_peak_perc: 95.50% → current / peak
used_memory_overhead: 852000 → internal overhead (dicts, expiry table, etc.)
used_memory_startup: 864000 → baseline memory at startup
used_memory_dataset: 1527136000 → data memory (used_memory - overhead)
used_memory_dataset_perc: 99.94% → dataset / (peak - startup)
allocator_allocated: 1528100000 → bytes allocated from jemalloc
allocator_active: 1953300000 → bytes in active jemalloc pages
allocator_resident: 2097100000 → bytes in resident jemalloc pages
total_system_memory: 8589934592 → total RAM on the machine
maxmemory: 2147483648 → configured maxmemory (2GB)
maxmemory_human: 2.00G
maxmemory_policy: allkeys-lru
mem_fragmentation_ratio: 1.37 → RSS / used_memory
mem_fragmentation_bytes: 569152000 → bytes "lost" to fragmentation
mem_not_counted_for_evict: 0
mem_replication_backlog: 1048576 → replication backlog size
mem_clients_slaves: 20512
mem_clients_normal: 84000
mem_cluster_links: 0
mem_aof_buffer: 8
active_defrag_running: 0
lazyfree_pending_objects: 0
lazyfreed_objects: 42831
Interpreting the Key Fields
mem_fragmentation_ratio = used_memory_rss / used_memory
- < 1.0 → Redis is using swap (critical, investigate immediately)
- 1.0–1.2 → healthy
- 1.2–1.5 → moderate fragmentation (normal for dynamic workloads)
-
1.5 → high fragmentation — consider
activedefragor restart
used_memory_overhead = memory used by Redis's internal data structures (the global keyspace dict, expiry table, per-client buffers). If this is a large fraction of used_memory, you have very small values (overhead dominates) — consider consolidating keys into Hashes.
mem_clients_normal = memory used by client output buffers. If this is large (> 10MB), you may have slow clients receiving data faster than they can consume it.
MEMORY USAGE: Per-Key Cost
MEMORY USAGE key [SAMPLES count]
Returns the exact number of bytes allocated for a key and its value, including all internal structures (robj, SDS, listpack nodes, etc.).
127.0.0.1:6379> MEMORY USAGE user:1001
(integer) 128
127.0.0.1:6379> MEMORY USAGE large:hash
(integer) 4194304 ← this hash is using 4MB
For collections, SAMPLES controls how many elements are sampled to estimate total cost (default 5). Use SAMPLES 0 for exact measurement on small collections.
Using MEMORY USAGE to find expensive keys:
#!/bin/bash
# Find the 20 most memory-hungry keys
redis-cli --scan | while read key; do
size=$(redis-cli MEMORY USAGE "$key" 2>/dev/null)
echo "$size $key"
done | sort -n -r | head -20
On a production instance with millions of keys, sample a representative subset:
redis-cli --scan --count 1000 | shuf | head -1000 | while read key; do
size=$(redis-cli MEMORY USAGE "$key" 2>/dev/null)
echo "$size $key"
done | sort -n -r | head -20
MEMORY DOCTOR
MEMORY DOCTOR
Returns a human-readable diagnosis. Possible outputs:
"Sam, I detected a few problems:
* High total allocator fragmentation: The RSS reported by the allocator is
suspicious. This could be caused by ...
* High rss overhead: ..."
Or for a healthy instance:
"Sam, I have detected no problems in the server memory subsystem."
Not a substitute for INFO memory, but a quick sanity check.
MEMORY MALLOC-STATS
MEMORY MALLOC-STATS
Dumps the full jemalloc allocator statistics — bin sizes, fragmentation per bin, active vs retained pages. Useful when you suspect allocator-level fragmentation rather than Redis-level issues.
Finding the Memory Culprits
Pattern 1: Large Hashes in hashtable Encoding
A Hash with > 128 fields (or any field > 64 bytes) switches from listpack to hashtable encoding. The memory cost jumps roughly 5x per element. Find them:
redis-cli --scan --pattern "user:*" | while read key; do
type=$(redis-cli TYPE "$key")
if [ "$type" = "hash" ]; then
len=$(redis-cli HLEN "$key")
encoding=$(redis-cli OBJECT ENCODING "$key")
if [ "$encoding" = "hashtable" ]; then
size=$(redis-cli MEMORY USAGE "$key")
echo "$size $key $len fields"
fi
fi
done | sort -n -r | head -20
Sign in to keep reading
The rest of this module is free — sign in with Google to unlock it and track your progress.
Sign in & RegisterDiscussion
0Join the discussion