8人参与 • 2025-06-11 • Redis
ziplist是一种特殊的“双向链表”,但其实并不是链表,而是一段连续的内存空间,可以在任意一端进行压入/弹出操作。并且该操作的时间复杂度是o(1)
结构如下图:
现在对每一个部分进行解释:
zlbytes
:存该压缩列表的总字节数,byte即字节zltail
:存最后一个节点到压缩列表的其实地址之间的字节数zllen
:存的是总entry的个数entry
:即节点zlend
:压缩列表的结束标志,并且值是固定的:0xff这里补充一点进制基础:
结合下图更容易理解:
下图是每个部分所占字节数:
有没有注意到一个问题,为什么这里的entry的长度是不确定的?
像数组,只要确定了数组的类型,就能知道其每个节点所占字节数,为什么这里的不确定的呢?
这就需要我们来聊聊entry的结构了 。
ziplist的entry不像普通双端链表那样记录前后节点的指针,因为记录2个指针要16个字节,比较浪费内存。
ziplist中的entry采用的如下的结构:
previous_entry_length
:存前一个节点的总字节数,占1或5个字节。
encoding
:存该节点的内容的编码,用来区分content是(自负床还是整数),并且存了 content的长度,占1,2或者5个字节稍后有详细解释
content
:存该节点的数据,可以是字符串或整数。
压缩列表的entry既然没有存前后2个节点的指针,那么怎么双向遍历呢?
先说正序:正序时,已知当前entry的起始地址,要知道当前节点的下一个节点,前面有提到过,压缩列表是连续的一片内存空间,所以只要将当前节点的起始地址加上该节点总占字节数()即可,那这个当前节点所占字节数怎么算呢?
节点所占字节数 = previous_entry_length所占字节数 + encoding所占字节数 + encoding里面的所存content的长度
也就是三个部分的字节数相加,只不过content所占字节数要通过encoding里面获取。
再说逆序:逆序时,已知当前entry的起始地址,只要用当前entry的起始地址减去previous_entry_length就是前一个节点的起始地址了。因为previous_entry_length存的就是前一个节点总占字节数。
前面2个比特位用来标记该content是字符串,以第一种为例
00标记该content是字符串,剩余6位存content的所占字节,2的6次方-1是63,所以content的长度最大值是63个字节。
这样说可能不太清楚,举例说明:
现在我们要存“ab” 和 “cd”这两个字符串,即第一个节点存ab,第二个节点存cd
首先存ab:
previous_entry_length:
encoding:
content:a的ascii值是97,就是二进制01100001;
转化成16进制是这样的:
然后来存cd:
previous_entry_length:
所以previous_entry_length = 00000101
encoding:
content:
所以整个ziplist是这样的
如果encoding是以11开始,就表示content存的是整数
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论