0
点赞
收藏
分享

微信扫一扫

redis源码之字符串

洛茄 2022-04-14 阅读 42
redis

redis源码-字符串

结构

redis 中的字符串叫SDS (simple dynamic string),结构如下:

struct SDS<T>{
    T capacity; // 数组容量
    T len; // 实际长度
    bytes flags; // 特殊标志位 无需关注
    byte[] content; // 数组内容 实际存放的值
}

capacity 和len 有点类似java中的ArrayList。一般来说redis就预分配空间,即capacity > len,为了支持append的操作。
T:泛型,可以根据数组的长度用byte、short、int、long 等表示,可见redis 将内存优化到了极致。
redis 规定字符串的长度不会超过512M,当新建string时,capacity = len,因为设计人员认为,一般不会用append的操作。当len>capacity 时,redis就会扩容。当redis key小于1M时,扩容是翻倍进行的,大于1M时,redis为了节省内存,每次扩容增加1M.

存储方式

redis 的字符串有两种存储方式。在长度特别短时,使用embstr,当长度超过44字节时,使用raw的形式存储。

## 查看存储方式:
> set len45 111111111122222222223333333333444444444455555
OK
> set len44 11111111112222222222333333333344444444445555
OK
> debug object  len45
Value at:0x7f13cce45960 refcount:1 encoding:raw serializedlength:29 lru:5761491 lru_seconds_idle:52
> debug object  len44
Value at:0x7fa70090eb80 refcount:1 encoding:embstr serializedlength:27 lru:5761519 lru_seconds_idle:102

那么问题来了,为什么是44字节呢?

对象头

所有redis对象都有一个对象头

struct RedisObject{

    int4 type; // 4bits 类型
    int4 encoding // 4bits 存储类型
    int24 lru; // 24bits 记录LRU信息  即 最后一次被访问的时间戳
    int32 reconf; //4bytes  引用计数
    void *ptr //8bytes 指向对象内容具体的位置
  
}

从对象头的结构可以看出,每个对象头占用16个字节(0.5+0.5+3+4+8)。而一个字符串SDS至少占3个字节(字符串长度小的时候capacity、len、flag占用一个字节),因此一个字符串至少占用19个字节(16+3 此时字符串没有任何长度)。
内存分配器分配的内存大小单位都是2/4/8/16/32/64字节。若想让内存分配器只分配一次(2/4/8/16/32/64 都是只分配一次),字符串的最大值是64(上面说过字符串最小为19个字节,因此字符串小的时候可以只分配一次额度),因此redis将只需要内存分配一次的字符串定义一种存储方式—embstr,需要分配多次的字符串定义另外一种存储方式—raw。因此,embstr和raw的分界线就是64字节。上面说过字符串最小为19个字节,由于字符串需要用null结尾,因此embstr存储形式的字符串的最大长度为64-19-1=44。

举报

相关推荐

0 条评论