虽然内部数据结构非常强大,但是创建一系列完整的数据结构本身也是一件相当耗费内存的工作,当一个对象包含的元素数量并不多,或者元素本身的体积并不大时,使用代价高昂的内部数据结构并不是最好的办法。
为了解决这一问题,Redis在条件允许的情况下,会使用内存映射数据结构来代替内部数据结构。
内存映射数据结构可以为用户节省大量的内存。不过,因为内存映射数据结构的编码和操作方式要比内部数据结构要复杂得多,所以内存映射数据结构所占用的CPU 时间会比作用类似的内部数据结构要多。
这一部分将对Redis目前正在使用的两种内存映射数据结构进行介绍。
整数集合
整数集合(intset)用于有序、无重复地保存多个整数值,它会根据元素的值,自动选择该用什么长度的整数类型来保存元素。
Intset是集合键的底层实现之一,如果一个集合:
1. 只保存着整数元素;
2. 元素的数量不多;
那么Redis就会使用intset来保存集合元素。
根据需要,intset可以自动从int16_t 升级到int32_t 或int64_t ,或者从int32_t 升级到int64_t 。
typedefstructintset {
// 保存元素所使用的类型的长度
uint32_tencoding;
// 元素个数
uint32_tlength;
// 保存元素的数组
int8_tcontents[];
} intset;
实例
现在,我们要要将一个长度为int32_t 的值65535 加入到集合中,intset需要执行以下步骤:
1. 将encoding 属性设置为INTSET_ENC_INT32 。
2. 根据encoding 属性的值,对contents 数组进行内存重分配。
3. 因为原来的3 个int16_t 值还“挤在”contents 前面的48 个位里,所以程序需要对它们进行移动和类型转换,从而让它们适应集合的新编码方式。
4. 最后,将新值65535 添加到数组:
•Intset用于有序、无重复地保存多个整数值,它会根据元素的值,自动选择该用什么长度的整数类型来保存元素。
•当一个位长度更长的整数值添加到intset时,需要对intset进行升级,新intset中每个元素的位长度都等于新添加值的位长度,但原有元素的值不变。
•升级会引起整个intset进行内存重分配,并移动集合中的所有元素,这个操作的复杂度为O(N) 。
•Intset只支持升级,不支持降级。
•Intset是有序的,程序使用二分查找算法来实现查找操作,复杂度为O(lgN) 。
压缩列表
Ziplist是由一系列特殊编码的内存块构成的列表,一个ziplist可以包含多个节点(entry),每个节点可以保存一个长度受限的字符数组(不以\0 结尾的char 数组)或者整数。
•字符数组
–长度小于等于63 (26 1)字节的字符数组
–长度小于等于16383 (214 1)字节的字符数组
–长度小于等于4294967295 (232 1)字节的字符数组
•整数
–4 位长,介于0 至12 之间的无符号整数
–1 字节长,有符号整数
–3 字节长,有符号整数
–int16_t 类型整数
–int32_t 类型整数
–int64_t 类型整数
ziplist是由一系列特殊编码的内存块构成的列表,它可以保存字符数组或整数值,它还是哈希键、列表键和有序集合键的底层实现之一。