(ZipList入门笔记一)ZipList的节点介绍
ZipList是 Redis 中一种非常紧凑、节省内存的数据结构 Ziplist(压缩列表) 的内部内存布局。它被用于存储元素较少的 List、Hash 和 Zset。
下面我们来详细介绍每一个节点的含义:
1. zlbytes
(ziplist bytes)
- 含义: 整个压缩列表占用的总字节数。
- 类型: 32位无符号整数(
uint32_t
),固定占用 4 个字节。 - 作用: 这个字段记录了 Ziplist 的总大小。有了它,程序无需遍历整个列表就能知道其边界,这在进行内存重分配(
realloc
)时非常有用,可以直接告诉内存管理器需要多大的空间。
2. zltail
(ziplist tail)
- 含义: 指向列表中最后一个元素(entry)的偏移量(offset)。
- 类型: 32位无符号整数(
uint32_t
),固定占用 4 个字节。 - 作用: 这个字段允许程序在 O(1) 的时间复杂度内定位到 Ziplist 的最后一个节点,而无需从头遍历。这使得从列表尾部进行 pop(弹出)等操作非常高效。
3. zllen
(ziplist length)
- 含义: 压缩列表中的节点(entry)数量。
- 类型: 16位无符号整数(
uint16_t
),固定占用 2 个字节。 - 作用: 提供了在 O(1) 时间复杂度内获取列表长度的能力。
- 特殊情况: 由于它只有16位,最大只能表示
65535
。如果 Ziplist 中的节点数超过或等于65535
,这个字段会被设置为特殊值65535
(FFFF
)。在这种情况下,要获取真实长度,就必须遍历整个列表来统计,时间复杂度会退化为 O(N)。不过,Ziplist 的设计初衷就是用于存储少量数据,所以这种情况很少见。
4. entry
(列表节点)
- 含义: 这部分是 Ziplist 的核心,用来存储实际的数据元素。图中的
entry1
,entry2
,entry3
代表连续存放的多个节点。 - 结构: 每个
entry
自身的结构也非常精巧,它由三个部分组成:previous_entry_length
(前一节点的长度): 这个字段记录了前一个节点所占用的总字节数。它的存在是实现从后向前遍历 Ziplist 的关键。通过当前节点的地址减去这个长度,就可以得到前一个节点的起始地址。这个字段本身的长度是可变的(1字节或5字节),以节省空间。encoding
(编码): 这个字段指明了content
部分的数据类型(是字符串还是整数)以及它的长度。编码字段本身也是变长的,通过不同的二进制位模式来表示不同的编码方式,实现了极致的空间优化。content
(内容): 实际存储的数据,可以是整数或一个字节数组(字符串)。其长度由encoding
字段决定。
5. zlend
(ziplist end)
- 含义: 压缩列表的结束标记。
- 类型: 8位无符号整数(
uint8_t
),固定占用 1 个字节。 - 值: 它的值永远是
255
(二进制11111111
,十六进制0xFF
)。 - 作用: 作为一个明确的终止符,当程序遍历列表时,一旦遇到这个值,就知道已经到达了列表的末尾。
总结
Ziplist 的设计精髓在于 “紧凑”。它不像常规链表那样为每个节点都使用前后指针(在64位系统上,一个指针就占8字节),而是通过存储前一节点的长度 (previous_entry_length
) 和利用连续内存布局,实现了双向遍历,从而极大地节省了内存。图中 zlbytes
, zltail
, zllen
这三个头部字段,共同为这个紧凑的结构提供了高效的宏观操作能力。
下一篇:
(ZipList入门笔记二)为何ZipList可以实现内存压缩,可以详细介绍一下吗