ZipList是一种特殊的 “双端链表” ,由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作,且该操作的时间复杂度是O(1)
ZipList结构如下:
ZipList中的entry结构如下:
Entry中encodeing的编码分为字符串和整数两种:
字符串:如果 encoding 是以“00” “01” “10” 开头,则证明contents是字符串,并且随着字符串长度的不同采用不同的编码方式:分别占用1个、2个或5个字节
如果 encoding 是以 “11” 开头,则证明 contents 中存放的是整数,此时encoding固定只占一个字节,根据不同的整数范围,定义了一些编码格式:
其中,当存放的整数范围在 0-12时,甚至会省去contents的内存消耗
ZipList的连锁更新问题:
ZipList 的每个Entry 都包含previous_entry_length 来记录上一个节点的大小,长度是 1 个或 5 个字节:
如果前一个节点的长度小于 254 个字节,则采用一个字节来记录
如果前一个节点的长度大于或等于 254个字节,则采用 5 个字节来记录,此时第一个字节为 0xfe ,后四个字节才是真实长度。
现在,假设有 N 个连续的,长度为 250-253 之间的 entry ,此时 previous_entry_length 属性用一个字节即可记录。
此时 ,当有一个大小为 254 个字节的 entry 插入ZipList 最前面,此时会导致后面 entry 的 previous_entry_length 用 5 个字节来存储当前插入节点的大小,会导致后一个 entry 的大小变得大于或等于 254 个字节,从而引发连锁反应,后面的 entry 的previous_entry_length也会变大,entry 也变大,此时会频繁的进行数据迁移,申请内存,销毁动作,使性能受到很大影响。
在进行新增、删除操作时都可能导致连锁更新的发生 ,但是由于产生连锁更新的条件比较苛刻,所以发生的概率极低。根据连续的 250-253 字节的 entry 的个数不同,产生连锁更新的影响大小也会不同。
ZipList特性:
1.压缩列表可以看做是一个连接内存的 ”双向链表“
2.列表的节点之间并不是通过指针连接,而是记录上一个节点和本节点长度来寻址,内存占用较低。
3.如果列表数据过多,导致链表过长,查询性能会受到影响
4.增、删较大的数据时有可能发生连锁更新问题