Understanding Redis Memory Model: Objects, Allocation, and Internal Encoding
This article explains Redis's memory model by describing how to query memory usage, the roles of used_memory, used_memory_rss, mem_fragmentation_ratio, and mem_allocator, and then dives into the internal structures such as redisObject, SDS, jemalloc, and the encoding strategies for strings, lists, hashes, sets, and sorted sets.
Introduction
Redis is one of the most popular in‑memory databases. By reading and writing data directly in memory, it dramatically improves read/write speed and is essential for high‑concurrency web services.
When using Redis you encounter five data types—string, hash, list, set, and sorted set—which give Redis an advantage over alternatives like Memcached.
Understanding the five object types and Redis's memory model helps you estimate memory consumption, optimise memory usage, and troubleshoot issues such as blocking or excessive memory fragmentation.
1. Redis Memory Statistics
Before analysing Redis memory you need to know how to obtain it. After connecting with redis-cli , run the INFO MEMORY command to display memory‑related information.
The most important fields are:
used_memory : total memory allocated by Redis's allocator (including virtual memory).
used_memory_rss : memory that the Redis process occupies in the operating system (includes allocator overhead, process code, and fragmentation).
mem_fragmentation_ratio : ratio of used_memory_rss to used_memory , indicating the degree of memory fragmentation.
mem_allocator : the memory allocator used by Redis (libc, jemalloc, or tcmalloc). The default is jemalloc.
When mem_fragmentation_ratio is around 1.03 (for jemalloc) the memory usage is considered healthy. Values greater than 1 indicate fragmentation; values less than 1 suggest that virtual memory is being used and may require investigation.
2. Redis Memory Allocation
Redis's memory consumption can be divided into four parts:
2.1 Data
The actual key‑value pairs stored in Redis. This part is accounted for in used_memory . Redis supports five object types, each of which may have multiple internal encodings.
2.2 Process Memory
The Redis server binary, constant pools, and other code‑related data occupy a few megabytes and are not allocated by jemalloc, so they are not counted in used_memory . Child processes created for AOF or RDB rewriting also consume memory but are excluded from the main process statistics.
2.3 Buffer Memory
Includes client output buffers, replication backlog buffers, and AOF buffers. These buffers are allocated by jemalloc and therefore appear in used_memory .
2.4 Memory Fragmentation
Fragmentation occurs when memory is allocated and freed repeatedly, especially with highly variable object sizes. It is not counted in used_memory but contributes to used_memory_rss . Restarting Redis can reduce fragmentation because the server reloads data from the dump file and re‑allocates memory more compactly.
3. Details of Redis Data Storage
Redis stores objects using several layers of abstraction: the redisObject wrapper, the Simple Dynamic String (SDS) structure, and the underlying memory allocator (jemalloc).
3.1 jemalloc
Redis is compiled with a memory allocator; the default is jemalloc because it reduces fragmentation. jemalloc divides memory into three size classes (tiny, small, large) and further splits each class into fixed‑size chunks. When an object needs 130 bytes, jemalloc allocates a 160‑byte chunk.
3.2 redisObject
The core structure that represents any Redis value:
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:REDIS_LRU_BITS; /* last access time */
int refcount;
void *ptr;
} robj;Field explanations:
type : identifies the logical data type (string, list, hash, set, sorted set).
encoding : indicates the internal representation (e.g., int, embstr, raw, ziplist, hashtable, intset, skiplist).
lru : records the last access time for LRU eviction.
refcount : reference count; values > 1 are shared objects (currently only integer strings).
ptr : points to the actual data (e.g., an SDS buffer or a linked‑list node).
3.3 Simple Dynamic String (SDS)
Redis does not use C‑style null‑terminated strings directly. Instead it uses SDS, which stores length and free space alongside the character buffer:
struct sdshdr {
int len;
int free;
char buf[];
};This design provides O(1) length queries, automatic reallocation on overflow, and safe binary data handling.
3.4 Object Types and Internal Encodings
String
Three possible encodings:
int : 8‑byte integer when the value fits in a signed long.
embstr : for strings ≤ 39 bytes; the redisObject and SDS are allocated as a single contiguous block.
raw : for strings > 39 bytes; redisObject and SDS are allocated separately.
When an embstr string is modified, Redis converts it to raw because embstr objects are read‑only.
List
Two possible encodings:
ziplist : a compact sequential memory layout used when the list has fewer than 512 elements and each element is ≤ 64 bytes.
linkedlist : a doubly linked list used otherwise.
Hash
Internal encoding can be either ziplist (same conditions as list) or a hashtable. The hashtable consists of dict , dictht , and dictEntry structures. Example of dictEntry :
typedef struct dictEntry {
void *key;
union { void *val; uint64_t u64; int64_t s64; } v;
struct dictEntry *next;
} dictEntry;When the number of entries exceeds 512 or any key/value exceeds 64 bytes, Redis switches from ziplist to hashtable.
Set
Encodings:
intset : stores integer elements compactly when the set has fewer than 512 members and all members are integers.
hashtable : used otherwise (values are stored as NULL ).
Structure of intset :
typedef struct intset {
uint32_t encoding;
uint32_t length;
int8_t contents[];
} intset;Sorted Set (ZSET)
Encodings:
ziplist : when the set has fewer than 128 elements and each member is ≤ 64 bytes.
skiplist : otherwise. The skiplist provides O(log N) average lookup time and is easier to implement than a balanced tree.
4. Summary
Redis's memory model combines a flexible allocator (jemalloc), a generic object wrapper ( redisObject ), and the SDS string type to achieve high performance and low fragmentation. Each logical data type can switch between compact and fast encodings based on size and cardinality, allowing Redis to optimise memory usage for a wide range of workloads.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.