压缩列表
听到“压缩”两个字,直观的反应就是节省内存。之所以说这种存储结构节省内存,是相较于数组的存储思路而言的。我们知道,数组要求每个元素的大小相同,如果我们要存储不同长度的字符串,那我们就需要用最大长度的字符串大小作为元素的大小(假设是20个字节)。存储小于 20 个字节长度的字符串的时候,便会浪费部分存储空间。
数组的优势占用一片连续的空间可以很好的利用CPU缓存访问数据。如果我们想要保留这种优势,又想节省存储空间我们可以对数组进行压缩。
但是这样有一个问题,我们在遍历它的时候由于不知道每个元素的大小是多少,因此也就无法计算出下一个节点的具体位置。这个时候我们可以给每个节点增加一个lenght的属性。
如此。我们在遍历节点的之后就知道每个节点的长度(占用内存的大小),就可以很容易计算出下一个节点再内存中的位置。这种结构就像一个简单的压缩列表了。
# Redis中压缩列表的构成
zlbytes:记录整个压缩列表占用的内存字节数,在对压缩列表进行内存重新分配或者使用zllen的位置时使用
zltail:记录压缩列表表尾字节距离压缩列表起始地址有多少字节,通过这个偏移量,程序无须遍历整个压缩列表就可以确定列表表尾字节点的地址
zllen:记录压缩列表包含的节点数量,当这个属性的至小于UINT_MAX(65535)时,这个属性的值就是压缩列表包含的节点数量。当这个值等于UINT_MAX时,节点的真实数量需要遍历整个列表计算得出
entryN:压缩列表包含的各个节点,节点的长度由节点包含的内容决定
例如下图,展示了一个总长为80字节,包含3个节点的压缩列表。如果我们有一个指向压缩列表起始地址的指针p,那么表尾节点的地址就是P+60。
# 节点的结构
previous_entry_length:以字节为单位,记录了压缩列表中前一个节点的长度。
encoding:记录了节点的content属性所保存数据的类型以及长度
content:负责保存节点的值,节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定。