Redis is often used to keep frequently accessed data in memory so applications can respond quickly without repeatedly querying a database. It can store session data, API responses, counters, user profiles, queues, and other information that applications need to access with low latency.
However, Redis memory usage can increase gradually until the server reaches its configured memory limit. When that happens, Redis may start evicting keys, reject write commands, or experience performance problems depending on its configuration and the type of workload.
The difficult part is that memory growth does not always indicate a memory leak. A cache may be storing more unique keys than expected, application code may be assigning excessively long expiration times, or individual values may be larger than they were originally. Fragmentation and memory used outside the main data structures can also affect the total memory consumed by the Redis process.
The best approach is to monitor memory trends, identify which data structures are growing, inspect expiration and eviction behavior, and compare Redis's reported memory with the memory available on the host.
This article explains how to detect Redis memory growth, investigate the likely causes, and prevent a cache from running out of memory in production.
Understand How Redis Uses Memory
Redis stores its data primarily in memory. Each key and value consumes memory, but the total cost is not limited to the raw value itself.
Redis also requires memory for data structures, key metadata, expiration information, client connections, replication buffers, persistence operations, and other internal work.
For example, a cache entry containing a short user identifier may appear small when viewed as a string. However, the key, value, allocator overhead, and associated metadata all contribute to the actual memory cost.
This explains why adding up the visible lengths of keys and values does not always match Redis's total memory consumption.
Before diagnosing memory growth, distinguish between three important measurements:
Used memory: Memory Redis reports as being used by the server.
RSS: Resident Set Size, which represents physical memory currently occupied by the Redis process.
Available host memory: The memory the operating system can still provide without excessive pressure or swapping.
These values are related, but they are not interchangeable.
A Redis instance can report a relatively stable used-memory value while RSS remains high because of memory fragmentation. Conversely, used memory can grow while the operating system still has available memory, giving you time to investigate before the situation becomes critical.
Check Redis Memory Statistics
Start by collecting the server's memory information.
Run the following command using redis-cli or an equivalent Redis client:
redis-cli INFO memory
The command returns memory-related fields that help explain how Redis is using resources.
Important fields include:
Field | What it tells you |
|---|
used_memory | Memory allocated by Redis according to its internal accounting |
used_memory_peak | Highest reported used-memory value since the peak was reset or the server started |
used_memory_rss | Resident memory occupied by the Redis process |
used_memory_dataset | Memory attributed to the dataset |
used_memory_overhead | Memory used for Redis overhead rather than the dataset itself |
maxmemory | Configured memory limit, or zero when no explicit limit is configured |
mem_fragmentation_ratio | Ratio of RSS to used memory, useful as a rough fragmentation indicator |
allocator_allocated | Memory allocated through the configured allocator, when reported |
allocator_active | Active memory reported by the allocator, when available |
allocator_resident | Resident memory reported by the allocator, when available |
Available fields depend on the Redis version and build. Review the output from your own instance rather than assuming every field is present.
Compare used memory with RSS
Suppose Redis reports the following illustrative values:
used_memory: 4294967296
used_memory_rss: 5368709120
maxmemory: 6442450944
In this example, Redis reports approximately 4 GiB of used memory, about 5 GiB of resident memory, and a configured memory limit of 6 GiB.
The difference between used memory and RSS may indicate allocator fragmentation or other resident-memory overhead. It does not automatically mean that Redis has a memory leak.
The configured maxmemory limit also should not be treated as the safe physical-memory limit for the entire host. Replication, persistence, other processes, and operating-system requirements may need additional memory.
A production system should maintain enough headroom to handle expected workload changes and temporary memory peaks.
Monitor Memory Growth Over Time
A single memory snapshot shows the current state, but it cannot tell you whether the dataset is growing steadily or experiencing a temporary spike.
Collect memory statistics at regular intervals and store the measurements in your monitoring system.
For example, you can run:
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO keyspace
These commands provide different views of the server:
INFO memory reports memory usage and allocator-related information.
INFO stats reports operational counters, including eviction and expiration activity.
INFO keyspace reports database-level key counts and expiration counts.
For automated monitoring, use a Redis client or monitoring exporter to collect the relevant fields instead of repeatedly parsing large command outputs manually.
Track at least the following metrics:
Used memory and RSS.
Configured maxmemory.
Total key count.
Expired and evicted keys.
Memory allocation and fragmentation indicators.
Host memory availability.
Client connections and replication-related memory where relevant.
Calculate memory growth rate
Comparing consecutive measurements helps identify whether memory consumption is increasing faster than expected.
For example, if used memory increases from 2.0 GiB to 2.4 GiB over four hours, the average growth rate is approximately 0.1 GiB per hour.
The calculation is:
Growth rate = (Current memory − Previous memory) / Elapsed time
This average is useful for trend analysis, but it does not predict the future perfectly. Redis memory usage may fluctuate as keys expire, cache entries are evicted, or large operations run.
For a better estimate, use multiple samples and distinguish normal daily patterns from sustained growth.
If memory is increasing consistently while the key count remains stable, investigate whether values are becoming larger, data structures are changing, or non-dataset memory is growing.
Identify Whether the Number of Keys Is Increasing
A growing key count is one of the most common reasons for Redis memory growth.
An application may accidentally generate a new key for every request, user action, or unique parameter combination. If those keys do not expire, the dataset can grow continuously.
For example, an API might cache responses using a key that includes a timestamp:
product:42:2026-10-23T09:00:01
product:42:2026-10-23T09:00:02
product:42:2026-10-23T09:00:03
If the timestamp changes on every request, the cache stores separate entries even when the underlying product data has not changed.
Check key counts with:
redis-cli INFO keyspace
You may see output similar to:
# Keyspace
db0:keys=150000,expires=120000,avg_ttl=3600000
This is illustrative output. It indicates the number of keys in the database, how many have expiration times, and the average remaining TTL as reported by Redis.
A growing key count is not automatically a problem. The important question is whether the increase matches the application's expected caching behavior.
Avoid running the KEYS command against a large production dataset just to count keys. It can block Redis while scanning the keyspace. Use INFO keyspace for counts and SCAN when you need to inspect keys incrementally.
Find Which Keys Consume the Most Memory
Once you know that memory is growing, identify the data structures responsible.
Redis provides the MEMORY USAGE command to estimate the memory consumed by an individual key.
For example:
redis-cli MEMORY USAGE user:profile:1042
The result is an estimated memory cost in bytes for that key, including relevant data-structure overhead.
You can also inspect the key's type and expiration:
redis-cli TYPE user:profile:1042
redis-cli TTL user:profile:1042
redis-cli MEMORY USAGE user:profile:1042
These commands help answer three questions:
What type of data is stored?
Does the key have an expiration?
How much memory does the key consume?
A TTL result of -1 generally means the key exists without an expiration. A result of -2 means the key does not exist at the time of the check.
Use SCAN for targeted inspection
If you suspect a particular key namespace is growing, use SCAN rather than KEYS.
For example:
redis-cli --scan --pattern "user:profile:*"
This returns matching keys incrementally. You can then inspect selected keys with MEMORY USAGE and TTL.
Be careful when scanning large databases or checking thousands of keys individually. Even commands that avoid blocking the server can create noticeable load when executed at a high rate.
For production investigations, sample a manageable number of keys or run the inspection against a replica where appropriate. Remember that a replica may have its own memory overhead and does not necessarily reproduce the primary's exact operational conditions.
Do not assume the largest key is the entire problem
A single oversized value may explain a sudden jump in memory. However, thousands of moderately sized keys can consume more memory collectively than one large key.
Look at both the largest entries and the overall distribution of key sizes. If your application uses hashes, sets, sorted sets, lists, or streams, investigate those data structures according to their expected growth patterns.
Check Expiration and Eviction Behavior
Expiration and eviction are two different mechanisms.
Expiration removes keys whose TTL has elapsed. Eviction removes keys when Redis needs to make room under a configured maxmemory policy.
A key with no expiration may remain in Redis indefinitely unless application code deletes it or an eviction policy removes it.
Inspect expiration behavior
Review the number of keys with expiration times and compare it with the total key count.
If the application is designed to cache short-lived API responses but many keys have no TTL, there may be a bug in the cache-writing code.
Set expiration when writing data that should be temporary. For example:
redis-cli SET cache:product:42 '{"id":42,"name":"Keyboard"}' EX 3600
This stores the value with a one-hour expiration.
In application code, prefer an atomic command or client-library operation that sets both the value and expiration together. Avoid writing the value first and setting the TTL in a separate operation if a failure between those operations could leave permanent keys.
Not every Redis key should expire. Persistent business data, durable queues, and other records may have different retention requirements. Apply TTLs according to the data's purpose.
Inspect eviction activity
Run:
redis-cli INFO stats
Look for the evicted_keys counter. This counter reports the number of keys evicted to make room for new data under the configured memory policy.
If evictions increase while application latency or cache misses rise, the memory limit may be too small for the workload, the cache may contain too much data, or the selected eviction policy may not fit the access pattern.
Also inspect the configuration:
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy
The maxmemory-policy determines what Redis does when memory reaches the configured limit.
Common policies include:
allkeys-lru: Evicts keys using an approximation of least recently used behavior across all keys.
allkeys-lfu: Evicts keys using an approximation of least frequently used behavior across all keys.
volatile-lru: Applies LRU eviction to keys that have an expiration.
volatile-lfu: Applies LFU eviction to keys that have an expiration.
volatile-ttl: Prefers expiring keys with the shortest remaining TTL.
noeviction: Rejects commands that would increase memory usage when the limit is reached.
The best policy depends on whether all keys are disposable cache entries or whether some keys must be retained.
If your Redis instance stores both cache entries and persistent application data, choosing an eviction policy without considering those data types can lead to unexpected behavior.
Investigate Memory Fragmentation
Redis's used-memory figure does not always match the memory consumed by the process at the operating-system level.
Memory allocators manage memory in blocks, and freed memory may not immediately be returned to the operating system. As a result, RSS can remain high even after the dataset shrinks.
Check the memory statistics:
redis-cli INFO memory
Compare used_memory, used_memory_rss, and the allocator fields available in your Redis build.
A high mem_fragmentation_ratio can indicate fragmentation, but it should not be interpreted in isolation. The ratio can also be misleading when used memory is small, and some memory differences are expected during normal operation.
If RSS remains high after a workload finishes and the dataset size falls, investigate allocator behavior and the process's memory profile before assuming keys are leaking.
Redis supports active defragmentation in compatible configurations and environments, but enabling it is not a universal solution. It can consume CPU resources, and its effectiveness depends on the allocator, data structures, and workload.
Test any defragmentation changes under representative load and monitor both memory usage and latency.
Understand Persistence and Replication Memory
Redis may require additional memory for operations that are not directly reflected in the size of the logical dataset.
Persistence operations such as RDB snapshots or AOF-related activity can create temporary memory pressure. During fork-based persistence operations, copy-on-write behavior may increase physical memory use when the parent process modifies pages that are shared with the child.
Replication can also require buffers and additional memory, particularly when the workload generates changes faster than a replica can consume them.
If memory usage rises suddenly during a snapshot or replication event, correlate the increase with persistence activity, replication health, and host-level memory metrics.
Do not automatically raise maxmemory to accommodate a temporary peak. First determine how much memory is required by the dataset, Redis overhead, persistence, replication, and other processes. A larger limit is useful only when the host or container has enough capacity to support it safely.
Set a Safe Memory Limit
Redis's maxmemory setting provides a boundary for memory-management behavior, but it is not a guarantee that total process RSS will never exceed that value.
Some memory used by Redis, client buffers, replication, persistence, and allocator overhead may not be handled in exactly the same way as the dataset under the configured limit.
Inspect the current setting:
redis-cli CONFIG GET maxmemory
If maxmemory is set to zero, Redis has no explicit maxmemory limit configured. The operating system or container may still impose a memory limit, so an unlimited Redis configuration can be risky.
Before setting a limit, calculate the memory available to Redis after accounting for the operating system, other processes, replication, and persistence-related peaks.
For example, a server with 8 GiB of physical memory should not automatically assign all 8 GiB to Redis. The safe limit depends on the environment, workload, and required headroom.
Change configuration through the appropriate deployment or managed-service mechanism. Where runtime CONFIG SET is permitted, remember that a runtime change may not persist after a restart unless the configuration is also updated through the supported configuration process.
Common Mistakes to Avoid
Treating every increase as a memory leak
Memory growth may be normal when the application caches more unique data. Compare key counts, key sizes, TTLs, and workload volume before concluding that the application has a leak.
Relying only on used_memory
A stable used_memory value does not guarantee that the Redis process's RSS is stable. Monitor both Redis statistics and host-level memory.
Running KEYS on a large production database
The KEYS command can block Redis while it examines the keyspace. Use INFO keyspace for counts and SCAN for incremental inspection.
Increasing maxmemory without checking host capacity
A larger limit can delay eviction, but it can also increase the risk of operating-system memory pressure or out-of-memory termination if the host lacks sufficient headroom.
Ignoring keys without expiration
A cache key that never expires can accumulate indefinitely. Review the application's key-generation logic and TTL requirements rather than assigning arbitrary expiration times to every key.
Best Practices for Production Redis Monitoring
Build a monitoring dashboard that shows used memory, RSS, maxmemory, key count, evictions, expiration activity, and host memory availability. Alert on sustained growth and low headroom rather than relying only on a single fixed threshold.
Track the rate of change, not just the current value. A Redis instance using 70% of its configured limit with stable usage may be healthier than one at 50% whose memory consumption is rising rapidly.
Define a TTL policy for each cache namespace. Document which keys are disposable, which require persistence, and which eviction policies are safe for the data they contain.
Test memory behavior under realistic load, including large values, high key cardinality, persistence operations, and replica lag. Review the impact of changes to maxmemory and eviction policies before deploying them.
Finally, treat Redis memory capacity as an application-design concern. Reducing duplicate cache entries, limiting unnecessary data, and avoiding unbounded key creation can be more effective than continually increasing server memory.
Advantages and Disadvantages of Proactive Memory Monitoring
Advantages
Detects memory growth before Redis reaches its configured limit.
Helps distinguish dataset growth from allocator fragmentation.
Makes unexpected key creation and missing expiration policies easier to identify.
Reduces the likelihood of sudden eviction spikes or rejected writes.
Provides evidence for capacity planning and cache-policy decisions.
Disadvantages
Detailed key inspection can create additional workload on busy instances.
Memory statistics require interpretation and may vary by Redis version.
Approximate eviction policies do not guarantee that every key is removed according to an exact global ranking.
Persistence and replication can create temporary memory peaks that are difficult to predict from dataset size alone.
Monitoring cannot replace appropriate application-level cache design.
Summary
Redis memory growth is easier to manage when you detect trends before the server reaches its limit. Start with INFO memory, INFO stats, and INFO keyspace to understand current usage, key counts, expiration activity, and eviction behavior.
Then inspect selected keys with MEMORY USAGE and TTL, investigate unexpected key creation, and compare used memory with RSS. If memory rises during persistence or replication activity, examine those operations and the host's available capacity.
Set maxmemory according to the actual environment, choose an eviction policy that matches the data, and apply expiration rules to cache entries that should be temporary. Avoid disruptive production-wide scans and make configuration changes only after measuring the likely cause.
The goal is not simply to keep Redis memory low. It is to maintain predictable cache behavior, protect important data, and give the application enough memory headroom to handle normal traffic and unexpected workload spikes.
Join the conversation! Your thoughts help the community grow.