压缩列表是列表键和哈希键的底层实现之一。压缩列表是为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构。

【压缩列表是一种数据结构,这种数据结构的功能是将一系列数据与其编码信息存储在一块连续的内存区域,这块内存物理上是连续的,逻辑上被分为多个组成部分,其目的是在一定可控的时间复杂读条件下尽可能的减少不必要的内存开销,从而达到节省内存的效果 ————大佬总结】

一.什么时候使用压缩列表?

两种情况:

当一个列表键只包含少量列表项,并且每个列表项要么是小整数值,要么就是长度比较短的字符串。

当一个哈希键只包含少量键值对,并且每个减值对的键和值要么是小整数值,要么就是长度表较短

二.  压缩列表的构成

一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或一个整数值。其就是一个字节数组(char *)。如图:

除了entryx外,一个压缩列表其它4部分是固定的。

Zlbytes:存储一个无符号整数,固定4个字节长度,用来存储压缩列表所占用的内存字节数。当对压缩列表进行内存重新分配时,不需要遍历整个列表来计算内存大小。

Zltail:存储一个无符号整数,固定4个字节长度,记录压缩列表尾节点距离起始地址有多少字节(偏移量),通过这个值,程序不需要遍历整个列表就可以确定表尾节点的地址。

Zllen:压缩列表包含的节点个数,固定两个字节长度,最大只能表示65535个节点,当节点数目超过65535个时,该值无效。需要遍历列表来计算节点的个数。

EntryX:列表节点,长度不定(长度由节点保存的内容决定),由列表节点紧挨着组成。

Zlend:压缩列表结尾标志,固定一个字节长度,固定值0xFF(十进制255)。

内存布局【压缩列表就是一块连续的内存区域】:

三,压缩列表的节点

每个压缩列表节点可以保存一个字节数组或一个整数值。结构如下图:

1. previous_entry_length

  单位为字节,记录压缩列表中前一个节点的长度。那么程序可以通过指正运算,根据当前节点的起始地址来计算出前一个节点的起始地址。压缩列表的从表尾向表头遍历的操作就是使用这个原理。

  如果前一个节点的长度小于254个字节,那么previous_entry_length长度为1个字节,前一个节点的长度就保存在这一个字节里

  如果前一个节点的长度大于等于254个字节,那么previous_entry_length长度为5个字节,第一个字节设置为x0FE(十进制254),之后的四个字节保存前一个节点的长度

2. encoding

保存了节点的content的内容类型和长度,encoding类型一共有两种,一种是字节数组,一种是整数。

  A,字节数组:

    当保存字节数组时,编码长度有三种情况:
      1字节:值的最高位00,content保存的值长度小于等于63字节

      2字节:值的最高位01,content保存的值长度小于等于16383字节

      5字节:值的最高位10,content保存的值长度小于等于4294967295字节

  B,整数:

    保存整数时,长度位一个字节,值的最高位用11开头

3. content

保存节点的值,节点的值可以是一个字节数组或整数,值的类型和长度由节点的encoding属性决定。

4. 总结:

我们发现encoding第一个字节的前2比特可以区分是字节数组(以及字节数组类型)还是整数;

是整数时,第3、4比特可以区分整数的类型;当content的前4个比特都是1时,后4个比特才能区分整数类型;

四,压缩列表的原理:

相信到这里,我们都明白了压缩列表的原理压缩列表并不是对数据利用某种算法进行压缩,而是将数据按照一定规则编码在一块连续的内存区域,目的是节省内存。

 

五,压缩列表的应用:

Redis中,不同的数据类型广泛地应用了压缩列表编码,整理如下表:

1. 问题思考

Redis为什么使用压缩列表?

使用压缩列表的好处是什么?

压缩列表的应用对与我们使用内存有没有什么启发?

2. 大佬的总结

Redis对于每种数据结构、无论是列表、哈希表还是有序集合,在决定是否应用压缩列表作为当前数据结构类型的底层编码的时候都会依赖一个开关和一个阈值,开关用来决定我们是否要启用压缩列表编码,阈值总的来说通常指当前结构存储的key数量有没有达到一个数值(条件),或者是value值长度有没有达到一定的长度(条件)。任何策略都有其应用场景,不同场景应用不同策略。为什么当前结构存储的数据条目达到一定数值使用压缩列表就不好?压缩列表的新增、删除的操作平均时间复杂度为O(N),随着N的增大,时间必然会增加,他不像哈希表可以以O(1)的时间复杂度找到存取位置,然而在一定N内的时间复杂度我们可以容忍然而压缩列表利用巧妙的编码技术除了存储内容尽可能的减少不必要的内存开销,将数据存储于连续的内存区域,这对于Redis本身来说是有意义的,因为Redis是一款内存数据库软件,想办法尽可能减少内存的开销是Redis设计者一定要考虑的事情。

另外,经过仔细琢磨,我认为使用压缩列表的好处除了节约内存之外,还有减少内存碎片的作用,我把这种行为叫做"合并存储",也就是将很多小的数据块存储在一个比较大的内存区域,试想想,如果我们将要存储的数据都是很小的条目,我们为每一个数据条目都单独的申请内存,结果是这些条目将有可能分散在内存的每一个角落,最终导致碎片增加,这是一件令人头疼的事情。

六,参考资料:

书籍:《redis设计与实现》

博客:https://my.oschina.net/andylucc/blog/715325,https://segmentfault.com/a/1190000015296224,https://blog.csdn.net/u012658346/article/details/51321337

转载于:https://www.cnblogs.com/inspred/p/10656073.html

《Redis设计与实现》之第七章:压缩列表相关推荐

  1. 《Reids 设计与实现》第七章 RDB 持久化

    <Reids 设计与实现>第七章 RDB 持久化 文章目录 <Reids 设计与实现>第七章 RDB 持久化 一.简介 二.RDB 文件的创建与载入 1.SAVE 命令执行时的 ...

  2. 思科计算机第七章答案,CCNA第七章 访问控制列表 练习

    原标题:CCNA第七章 访问控制列表 练习 访问控制列表 1 在哪一配置中,出站 ACL 位置优于入站 ACL 位置? A. 将 ACL 应用至出站接口以在数据包退出接口前筛选来自多入站接口的数据包时 ...

  3. 计算机反求设计的一般步骤,第七章反求工程概述.pptx

    第七章 反求工程概述与创新设计; 7.1反求工程概述;7.1.1反求设计 反求工程首先是要进行反求分析,反求设计与传统的产品正向设计方法不同,他根据已存在的产品或零件来构造产品的工程设计模型或概念模型 ...

  4. Redis的设计与实现之整数集合和压缩列表

    整数集合(intset) 整数集合概念 整数集合是一个集合(set) 整数集合里只包含整数,并且集合元素不能太多 整数集合不会有重复的元素(有重复元素集合就没意义了) 整数集合的实现方式 typede ...

  5. Redis设计与实现 笔记 第十七章 集群 cluster

    集群 Redis 集群是 Redis 提供的分布式数据库方案,集群通过分片来进行数据共享,并提供复制和故障转移功能 17.1 节点 一个 Redis 集群通常由多个节点组成,在刚开始的时候,每个节点都 ...

  6. 《Redis设计与实现》第十一章 AOF持久化

    第十一章 AOF持久化 11.1 AOF持久化的实现 AOF持久化功能实现分为命令追加.文件写入.文件同步三个步骤. 11.1.1 命令追加 当AOF持久化功能出于打开状态时,服务器执行完一个写命令之 ...

  7. 算法设计与分析基础 第七章谜题

    习题7.1 6. 祖先问题要求在一棵给定的n顶点二叉树中,确定一个顶点u是否是顶点v的祖先.设计一个属于O(n)的输入增强算法,使我们可以在常量时间内获得树的每一对顶点的足够信息,来对问题求解. 分析 ...

  8. 《Redis设计与实现》第4章 字典

    目录​​​​​​​ 第4章 字典 4.1 字典的实现 4.2 哈希算法 4.3 解决键冲突 4.4 rehash 4.5 渐进式reha

  9. 《redis 设计与实现》读书笔记

    大家好,我是烤鸭:     <redis 设计与实现>,读书笔记. 第一部分 数据结构与对象 第2章 简单动态字符串 Redis 使用SDS 作为字符串表示. O(1) 复杂度获取字符串长 ...

  10. 《redis设计与实现》 读书笔记

    <redis设计与实现> 作者:黄健宏 读书笔记 一.前言 什么是redis: Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数 ...

最新文章

  1. 一个十分简短的Tween
  2. plt.acorr()函数使用实例-ValueError: object too deep for desired array
  3. 电脑端跳转手机版的php代码,帝国CMS电脑端自动跳转到手机端移动端的方法
  4. Qt Post上传图片文件到服务器
  5. android天气查询(一)websevice之ksoap2软件包的使用
  6. java高效字符串首字母大小写转换
  7. scala语言的底层是java实现的_2020了,每个程序员都该学习的 5 种开发语言
  8. java中的single_解析java泛型(一)
  9. 一个Camel Multicast组件聚合策略问题的解决过程
  10. SpringBoot集成Redis分布式锁以及Redis缓存
  11. sqlserver查询本周、上周、今天、昨天、本月、上月数据
  12. 通过利用“业务映射”来构建敏捷组织
  13. logo语言是计算机语言吗,LOGO语言的编程
  14. linux在服务器压缩文件夹,Linux服务器压缩文件夹
  15. WPF编程,Live Charts使用说明(51)——X轴Y轴同时赋值的一种方法
  16. 魂斗罗4 java 7723_FC魂斗罗4游戏下载-魂斗罗4FC无敌修改版下载-电玩咖
  17. Android 高级工程师面试(二)
  18. Android系统移植与调试之-------build.prop文件详细赏析
  19. opencv中的人脸检测案例
  20. spSellProduct 中,Begin Transaction 和 Commit Transaction 语句被包装在 Begin Try 和 End Try 块之间

热门文章

  1. SQL Case when 的使用方法
  2. CoreAnimation动画
  3. 配置cisco路由器特定时间重启
  4. onvif规范的实现:onvif开发常用调试方法 和常见的segmentation fault错误
  5. 8个开发必备的PHP功能
  6. kinect+java3d+robot开发备忘录
  7. 学会处理ASP.NET的页面和请求状态信息 (转载)
  8. 全新界面改版+实用功能上线 高德地图新版全体验
  9. org.apache.log4j.Logger详解
  10. 如何运营一个合法的经营性网站?办理经营性ICP证!