文章目录

  • 小对象压缩存储(ziplist)
  • 存储界限
  • 内存回收机制
  • 内存分配算法


小对象压缩存储(ziplist)

如果 Redis 内部管理的集合数据结构很小,它会使用紧凑存储形式压缩存储。

Redis 的 ziplist 是一个紧凑的字节数组结构,如下图所示,每个元素之间都是紧挨着的。

redis 设置list 大小 redis 固定大小list_Redis


如果它存储的是 hash 结构,那么 key 和value 会作为两个 entry 相邻存在一起。

redis 设置list 大小 redis 固定大小list_数据库_02


如果它存储的是 zset,那么 value 和 score 会作为两个 entry 相邻存在一起。

redis 设置list 大小 redis 固定大小list_redis_03


Redis 的 intset 是一个紧凑的整数数组结构,它用于存放元素都是整数的并且元素个数较少的 set 集合。

如果整数可以用 uint16 表示,那么 intset 的元素就是 16 位的数组,如果新加入的整数超过了 uint16 的表示范围,那么就使用 uint32 表示,如果新加入的元素超过了 uint32 的表示范围,那么就使用 uint64 表示,Redis 支持 set 集合动态从 uint16 升级到 uint32,再升级到 uint64。

redis 设置list 大小 redis 固定大小list_redis 设置list 大小_04


redis 设置list 大小 redis 固定大小list_redis_05


如果 set 里存储的是字符串,那么 sadd 立即升级为 hashtable 结构。

存储界限

当集合对象的元素不断增加,或者某个 value 值过大,这种小对象存储也会被升级为标准结构。Redis 规定在小对象存储结构的限制条件如下:

redis 设置list 大小 redis 固定大小list_redis 设置list 大小_06

内存回收机制

Redis 并不总是可以将空闲内存立即归还给操作系统。
如果当前 Redis 内存有 10G,当你删除了 1GB 的 key 后,再去观察内存,你会发现内存变化不会太大。原因是操作系统回收内存是以页为单位,如果这个页上只要有一个 key 还在使用,那么它就不能被回收。Redis 虽然删除了 1GB 的 key,但是这些 key 分散到了很多页面中,每个页面都还有其它 key 存在,这就导致了内存不会立即被回收。
不过,如果你执行 flushdb,然后再观察内存会发现内存确实被回收了。原因是所有的 key 都干掉了,大部分之前使用的页面都完全干净了,会立即被操作系统回收。
Redis 虽然无法保证立即回收已经删除的 key 的内存,但是它会重用那些尚未回收的空闲内存。

内存分配算法

Redis 为了保持自身结构的简单性,在内存分配这里直接做了甩手掌柜,将内存分配的细节丢给了第三方内存分配库去实现。目前 Redis 可以使用 jemalloc(facebook) 库来管理内存,也可以切换到 tcmalloc(google)。因为 jemalloc 相比 tcmalloc 的性能要稍好一些,所以 Redis 默认使用了 jemalloc。