当前位置: 首页 > news >正文

(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 自身的结构也非常精巧,它由三个部分组成:
    1. previous_entry_length (前一节点的长度): 这个字段记录了前一个节点所占用的总字节数。它的存在是实现从后向前遍历 Ziplist 的关键。通过当前节点的地址减去这个长度,就可以得到前一个节点的起始地址。这个字段本身的长度是可变的(1字节或5字节),以节省空间。
    2. encoding (编码): 这个字段指明了 content 部分的数据类型(是字符串还是整数)以及它的长度。编码字段本身也是变长的,通过不同的二进制位模式来表示不同的编码方式,实现了极致的空间优化。
    3. content (内容): 实际存储的数据,可以是整数或一个字节数组(字符串)。其长度由 encoding 字段决定。

5. zlend (ziplist end)

  • 含义: 压缩列表的结束标记。
  • 类型: 8位无符号整数(uint8_t),固定占用 1 个字节。
  • 值: 它的值永远是 255 (二进制 11111111,十六进制 0xFF)。
  • 作用: 作为一个明确的终止符,当程序遍历列表时,一旦遇到这个值,就知道已经到达了列表的末尾。

总结

Ziplist 的设计精髓在于 “紧凑”。它不像常规链表那样为每个节点都使用前后指针(在64位系统上,一个指针就占8字节),而是通过存储前一节点的长度 (previous_entry_length) 和利用连续内存布局,实现了双向遍历,从而极大地节省了内存。图中 zlbytes, zltail, zllen 这三个头部字段,共同为这个紧凑的结构提供了高效的宏观操作能力。

下一篇:

(ZipList入门笔记二)为何ZipList可以实现内存压缩,可以详细介绍一下吗

http://www.dtcms.com/a/316592.html

相关文章:

  • 【RH124 问答题】第 6 章 管理本地用户和组
  • ⭐CVPR2025 MatAnyone:稳定且精细的视频抠图新框架
  • LLM开发——语言模型会根据你的提问方式来改变答案
  • Android与Flutter混合开发:页面跳转与通信完整指南
  • 深入剖析 RAG 检索系统中的召回方式:BM25、向量召回、混合策略全解析
  • Go语言 string
  • stm32项目(21)——基于STM32和MPU6050的体感机械臂开发
  • 跨尺度目标漏检率↓82.4%!陌讯多尺度融合算法在占道经营识别的实战优化
  • 结构化开发方法详解:软件工程的奠基性范式
  • 机器学习——贝叶斯
  • Android 之 Kotlin中的协程(Dispatchers.IO)
  • Android UI 组件系列(十一):RecyclerView 多类型布局与数据刷新实战
  • ara::log::LogStream::WithTag的概念和使用案例
  • 鸿蒙开发--web组件
  • Java技术栈/面试题合集(5)-SpringBoot篇
  • SpringBoot3.x入门到精通系列:4.1 整合 MongoDB 详解
  • 《四种姿势用Java玩转AI大模型:从原生HTTP到LangChain4j》
  • Ubuntu24.04环境下非DOCKER方式安装Mysql5.7
  • 今日行情明日机会——20250805
  • 呼叫中心系统录音管理功能的应用
  • 初学docker
  • 深度拆解Dify:开源LLM开发平台的架构密码与技术突围
  • QUdpSocket发送组播和接受组播数据
  • 【类与对象(上)】C++封装之美:类与this指针解析
  • Nginx 单一端点上高效部署多个 LLM 模型
  • ES 模块动态导入
  • 海上电磁波传播:两径模型 vs 抛物方程模型传播损耗对比
  • 37.字典树
  • Redis集群模式下确保Key在同一Slot的实现方法
  • 按位运算 - C++