注:主要内容整理来自redis中几种哈希函数的研究
哈希就是离散算法
将一个键值转换成我们需要的数组索引下标的方法
Redis算法 LRU
LRU(Least Recently Used)最近最少使用统计算法
当Redis使用的内存超出设置的可以最大使用内存后
Redis会通过LRU的配置来回收内存
Redis对象的lru是用1<<24 - 1长度的字节表示的
可以连续标识194天的数据
Redis这里的LRU算法是近似算法
不是完全精确地获取到最合理的答案
而是按照采样结果查找到一个比较近似的结果
这个结果可能不是最合理的
但肯定不是最坏的
Redis算法 引用计数
Redis的内存回收算法采用
引用计数算法
通过增减对象的引用计数来判断
是否需要回收对象的内存
- 优点
- 代码逻辑清晰
- 不会有集中清理数据时造成的假死现象
- 缺点
- 无法解决循环引用问题(无视弱指针吧)
- 增加/减少引用数时的函数要对称,不能漏掉(c里面没有构造析构函数)
Redis 源码分析-quicklist
Redis 源码分析-ziplist
ziplist本质上就是字符串数组
当存储元素数量<UINT16_MAX时,可以直接读取长度
当存储元素数量>=UINT16_MAX时,需要遍历整个ziplist才能获取长度
采用了不同的编码来对数字,字符串存储进行了压缩
- 结构
<总字节数(4字节)><最后一个元素的偏移量(从头开始算)(4字节)><总元素个数(2字节)><数据(不定字节)>…<0xFF结尾标记(1字节)> - 数据的结构
- 头
- 前一个数据的编码类型和长度
- 当长度小于0xFE时,是一个字节
- 当长度大于等于0xFE时,是5个字节(第一个字节+4个字节的长度信息)
- 当前数据的编码类型和长度
第一个字节的前两位- 字符串
- 00??????
数据头总共占用一个字节
后六位表示字符串长度 - 01??????|????????
数据头总共占用两个字节
后14位表示字符串长度 - 10______|????????|????????|????????|????????
数据头总共占用5个字节
后4个字节表示字符串长度
- 00??????
- 数字
- 11000000
表示int16_t
后面两个字节为具体数据 - 11010000
表示int32_t
后面4个字节为具体数据 - 11100000
表示int64_t
后面8个字节为具体数据 - 11110000
表示int24_t
后面3个字节为具体数据 - 11111110
表示int8_t
后面1个字节为具体数据 - 11110001-11111101
直接表示0-12的值
后面没有数据
值直接就在当前字节中
其中
11110001 0
11110010 1
…
11111101 12
就是字节后4位的值直接转化为整数
然后-1所得的值
结尾不是1110是因为1110为int8_t
结尾不是1111是因为1111为ziplist结尾标记
- 11000000
- 字符串
- 前一个数据的编码类型和长度
- 数据
根据数据长度定义的连续字符串
- 头
相关文件
- ziplist.h
- ziplist.c
Redis 源码分析-skiplist
Redis 源码分析-intset
Redis 源码分析-哈希表
Redis 源码分析-压缩map
本质上就是char*
字符串
通过指定的格式排列的数据结构
基本格式
1 | <zmlen> // 当zmlen小于254时,记录的是键值对的个数,当等于254时,表示需要遍历整个zipmap才能指导具体的长度 |
1 | #define ZIPMAP_BIGLEN 254 // zm的长度上限,当数据长度超过254时,使用254标记,并将后4(根据unsigned int长度变化)为记录为数据长度 |
相关文件
- zipmap.h
- zipmap.c