05-Redis的内存对象及内部编码_List

列表(list)用来存储多个有序的元素; 一个列表可以存储2^32-1个元素。
Redis中的列表支持两端插入和弹出,并可以获得指定位置(或范围)的元素,可以充当数组、队列、栈等。

1 内部编码
列表的内部编码可以是压缩列表(ziplist)或双端链表(linkedlist)

  • 双端链表
    与双链表定义一致,引入了链表节点,并在此基础上增加头尾节点构建双端链表
    链表节点listNode如下定义:
/* Node, List, and Iterator are the only data structures used currently. */  
/* 
 * 链表节点 
 */  
typedef struct listNode {  
    // 前驱节点  
    struct listNode *prev;  
    // 后继节点  
    struct listNode *next;  
    // 值  
    void *value;  
} listNode;  

链表如下定义:

/* 
* 链表 
*/  
typedef struct list {  
   // 表头指针  
   listNode *head;  
   // 表尾指针  
   listNode *tail;  
   // 节点数量  
   unsigned long len;  
   // 复制函数  
   void *(*dup)(void *ptr);  
   // 释放函数  
   void (*free)(void *ptr);  
   // 比对函数  
   int (*match)(void *ptr, void *key);  
} list;  

双端链表结构如下图所示:
05-Redis的内存对象及内部编码_List_第1张图片

通过图中可以看出,双端链表同时保存了表头指针和表尾指针,并且每个节点都有指向前和指向后的指针;链表中保存了列表的长度;dup、free和match为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值。而链表中每个节点指向的是type为字符串的redisObject。

  • 压缩列表
    压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块(而不是像双端链表一样每个节点是指针)组成的顺序型数据结构。
    05-Redis的内存对象及内部编码_List_第2张图片
  • zlbytes记录整个压缩列表占用的内存字节数,在对压缩列表进行内存重分配或计算
  • zlend的位置时使用
  • zltail记录压缩列表尾节点距离压缩列表的起始地址有多少字节,通过这个偏移量,可以直接确定尾节点的位置
  • zllen记录压缩列表包含的节点数量
  • entryX表示各种节点,数量和长度不一定
  • zlend用于标记压缩列表的末端。

如图,如果有一个指针p指向该压缩列表,则尾巴节点的长度就是指针加上偏移量179(十六进制0xb3=16*11+3=179),列表的长度zllen为5,表示压缩列表包含5个节点。zlbytes为0xd2表示压缩列表的总长为210字节。

05-Redis的内存对象及内部编码_List_第3张图片
由上可知,每个压缩列表的节点可以保存一个字节数组或者一个整数值,那么每个节点肯定也有自己的结构。

与双端链表相比,压缩列表可以节省内存空间,但是进行修改或增删操作时,复杂度较高
因此当节点数量较少时,可以使用压缩列表;但是节点数量多时,还是使用双端链表划算

压缩列表不仅用于实现列表,也用于实现哈希、有序列表;使用非常广泛。

你可能感兴趣的:(redis)