先给一个Redis分析内存占用的网址: http://www.redis.cn/redis_memory/
这个工具会给我们一个内存占用分析,示例如下图:
我们在使用Redis的时候,String 类型是我们使用最多的,他也是唯一的一个非集合类型。
然而String类型并不是适用于所有场合的,它有一个明显的短板,就是它保存数据时所消耗的内存空间较多。
为什么String类型的占用的空间比较大呢,那是因为他除了记录实际数据,String 类型还需要额外的内存空间记录数据长度、空间使用等信息,这些信息也叫作元数据。当实际保存的数据较小时,元数据的空间开销就显得比较大了。
当你保存 64 位有符号整数时,String 类型会把它保存为一个 8 字节的 Long 类型整数,这种保存方式通常也叫作 int 编码方式。但是,当你保存的数据中包含字符时,String 类型就会用简单动态字符串(Simple Dynamic String,SDS)结构体来保存。
其中SDS的保存占用的内存如下所示:
在 SDS 中,buf 保存实际数据,而 len 和 alloc 本身其实是 SDS 结构体的额外开销。
然而,除了SDS的额外开销,String类型还有一个RedisObject 结构体(包含了八个字节的元数据和八个字节的指针)的开销,如下图所示:
为了解决上面提到的String类型占用内存过多的情况,我们可以使用压缩表来存储。
压缩列表之所以能节省内存,就在于它是用一系列连续的 entry 保存数据。
Redis 基于压缩列表实现了 List、Hash 和 Sorted Set 这样的集合类型,这样做的最大好处就是节省了 dictEntry 的开销。当你用 String 类型时,一个键值对就有一个 dictEntry,要用 32 字节空间。但采用集合类型时,一个 key 就对应一个集合的数据,能保存的数据多了很多,但也只用了一个 dictEntry,这样就节省了内存。
Hash 类型设置了用压缩列表保存数据时的两个阈值,一旦超过了阈值,Hash 类型就会用哈希表来保存数据了。这两个阈值分别对应以下两个配置项:
hash-max-ziplist-entries:表示用压缩列表保存时哈希集合中的最大元素个数。
hash-max-ziplist-value:表示用压缩列表保存时哈希集合中单个元素的最大长度。