压缩列表的构成
压缩列表是列表键和哈希键的底层实现之一,当一个列表键只包含少量列表项,并且每个列表项都是小整数或较短字符串,则用压缩列表作为底层实现
压缩列表是为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构
- zlbytes:记录整个压缩列表所占用的内存字节数,在内存重分配或zlend位置时使用
- zltail:记录压缩列表表尾节点距压缩列表的起始地址有多少字节,通过该偏移量,可无须遍历整个压缩列表就可以确定表尾节点的地址
- zllen:记录了压缩列表包含的节点数量
- entryX:压缩列表包含的各个节点,节点长度由节点包含的内容决定
- zlend:特殊值oxFF,用于标记压缩列表的末端
压缩列表节点的构成
previous_entry_length
以字节为单位,记录压缩列表前一个节点的长度。所以可以通过指针运算,根据当前节点的起始地址得到前一个节点的起始地址,用于从表尾到表头的遍历
指向表尾节点的指针 可以通过压缩列表的起始地址的指针加上zltail
encoding
记录节点的content属性所保存数据的类型及长度
content
负责保存节点的值,值的类型和属性由encoding决定
连锁更新
如果在压缩列表中,有多个介于250-153字节的节点e1-eN,记录这些节点的长度只需要1字节长的previous_entry_length,所以e1-eN所有节点的previous_entry_length都是1字节长
但如果将一个大于254字节的新节点new加入压缩列表的头节点,则new成为e1的前置节点。而这样e1的previous_entry_length属性不足以保存new的长度,所以进行空间重分配,变成5字节大小
这样e1的长度大于254字节了,e2的previous_entry_length也不足以保存e1的长度,也扩展成5字节大小。这样就进行连续多次空间扩展,即连锁更新
删除节点也会引发连锁更新
连锁更新在最坏情况下需要对压缩列表进行N次空间重分配操作,每次操作最坏O(N),所以连锁更新最坏时间复杂度为 O ( N 2 ) O(N^2) O(N2).
但是发生的机率比较低:1. 恰好有多个连续的,长度介于250-153字节的节点的情况并不多见 2. 即使出现连锁更新,只要被更新的节点数量不多,就不会对性能有影响所以平均复杂度为O(N)
连锁更新,只要被更新的节点数量不多,就不会对性能有影响所以平均复杂度为O(N)