在Redis中,当你对一个键值对执行添加(如使用SET命令)后执行删除(如使用DEL命令)操作时,内存通常会得到释放,但这并不是绝对的,具体取决于Redis的内存管理机制以及所使用的内存分配器。
1.原因总结:
即时性
内存分配策略
内存碎片
延迟释放
内存紧缩
即时性:在大多数情况下,当你使用DEL命令删除一个键值对时,Redis会立即释放该键值对所占用的内存空间。这是因为Redis的内存管理是基于键值对的,当键值对被删除时,其占用的内存应该被标记为可回收。
内存分配策略:Redis使用内存分配策略来管理内存,这意味着即使我们已经删除了大量的key,但内存却依旧未释放。此类现象常见于使用jemalloc和glibc内存分配器的Redis。当内存分配器检测到内存碎片时,它可能会暂时保留这些内存,以便将来更高效地分配内存给新的key。
内存碎片:内存碎片是另一个可能导致内存依旧未释放的原因。当我们不断地添加和删除key时,内存中可能会产生许多小的空闲区域。这些碎片化的内存可能无法立即被释放,从而导致内存使用量保持不变。延迟释放Redis使用延迟释放策略来避免因频繁释放内存而导致的性能下降。这意味着当我们删除大量的key时,这些key所占用的内存并不会立即释放。相反,Redis会在后台慢慢地回收这些内存,以减少对性能的影响。
内存紧缩:为了解决内存未释放的问题,我们可以尝试使用内存紧缩功能。这是一个手动操作,可以通过执行MEMORY PURGE命令来实现。内存紧缩会将内存中的空闲空间归还给操作系统,从而降低Redis的内存占用。
2.删除策略
redis在删除过期key的时候,不可能时时刻刻都遍历所有被设置过期时间的key来检测数据是否已经达到过期时间,然后再对它进行删除。所以有三种删除的方式
立刻删除
惰性删除
定期删除
一、立刻删除
立刻删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是立刻删除对cpu是最不友好的。因为删除操作会占用cpu的时间,如果刚好碰到了cpu很忙的时候,比如正在做交集或者排序等计算,那么就会给cpu造成额外压力,让cpu忙死。这会产生大量的性能消耗,同时也会影响数据的读取操作。
总结:对cpu不友好,用处理器性能换取存储空间(拿时间换空间)
二、惰性删除
数据到达过期时间,不做处理。等下次访问该数据的时候判断,是否过期,假如没过期则返回;假如已过期,删除返回不存在。惰性删除的缺点是对内存不友好。
总结:对内存不友好,用存储空间换取处理器性能(拿空间换时间)
三、定期删除
定期删除策略是前两种策略的折中。
定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。
周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度。有两个特点:
cpu性能占用设置有峰值,检测频度可自定义设置。
内存压力不是很大,长期占用内存的冷数据会被持续清理。
总结:周期性抽查存储空间(随机抽查,重点抽查),有漏网之鱼
举例:
redis默认每100ms检查是否有过期的key,有过期key则删除。注意:redis不是每隔100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms全部检查,redis直接进去icu)。因此如果只采用定期删除策略,会导致很多key到时见没有删除。
定期策略的难点是不确定删除操作执行的时长和频率:如果删除操作执行的太频繁或者执行的时间太长,定期删除策略就会退化成立即删除策略,以至于将CPU时间过去的消耗在删除过期键上面。如果删除操作执行的太少或者执行的时间太短,定期删除策略又会和惰性删除策略一样,出现浪费内存的情况。因此,如果采用定期删除策略的话,服务器必须根据情况,合理地设置删除操作的执行时长和执行频率。
解决方案
要解决这个问题,有两种方法:
方法一:手动触发内存回收你可以手动触发Redis的内存回收机制,即通过命令"redis-cli redis-forge"来启动Redis的内存回收线程,这将会强制Redis释放掉未使用的内存。但是这种方法会暂停Redis的写入操作,所以在执行此操作之前,最好先备份好你的数据。
方法二:修改Redis配置文件你也可以通过修改Redis的配置文件来控制内存回收机制的行为。具体来说,你可以修改以下两个参数:maxmemory-policy: 这个参数定义了当Redis达到最大内存限制时如何释放内存。默认值为noeviction,即Redis不会主动删除任何键。你可以将其修改为volatile-lru或者volatile-random,指定Redis优先删除过期键或随机删除键,来尽可能释放更多的内存。maxmemory-samples: 这个参数定义了每次扫描内存回收池的键的数量。默认值为5,你可以将它增加到100或更高,以提高内存回收效率。
注意:
手动触发Redis内存回收是否会有副作用?
手动触发Redis内存回收会暂停Redis的写入操作,因此在执行此操作之前,最好先备份好你的数据。
为什么要修改maxmemory-policy和maxmemory-samples参数?
修改这些参数可以控制Redis内存回收机制的行为,尽可能释放更多的内存。
已经删除了大量的键,为什么Redis的内存依旧未释放?
这是由于Redis的内存回收机制不是立即执行的,而是通过后台异步方式进行的。
删除key后,为什么内存使用量没有显著下降?
这可能是由于内存分配策略、内存碎片、延迟释放等原因导致的。要解决这个问题,可以尝试执行MEMORY PURGE命令进行内存紧缩。
如何检查Redis中的内存碎片?
可以使用INFO MEMORY命令查看内存相关的信息,包括内存碎片率等。