zoukankan      html  css  js  c++  java
  • Redis字符串结构

    【SDS结构】
    Redis中字符串的结构叫SDS,即Simple Dynamic String。它的结构是一个带长度信息的字节数组。

    struct SDS<T>{
    T capacity;
    T len;
    byte flags;
    byte[] content;
    }

    1.capacity>=len
    content中存储了真正的字符串内容,capacity和len表示分配数组的长度和字符串的实际长度。
    如图所示,除了包含当前的len长度字符串的字节内容,还会冗余一部分空间为后续的追加准备:

    但需要注意的是,创建字符串的时候,len=capacity,不会留冗余空间,因为绝大多数场景下,我们不会使用append操作来修改字符串。
    2.扩容规则
    之前提到过字符串的长度在1M以下是翻倍扩容,大于1M时扩容每次增加1M,到512M封顶。
    当字符串长度增加时(append新内容),直接追加到冗余的空间,当冗余空间不够时,就会分配新数组,然后将旧的数组分配到新数组中。
    3.T
    SDS结构中使用了泛型,也是为了节省空间。当字符串比较短时,这里分配的记录长度的结构是byte(1个字节)或者short(2个字节)...不同长度的字符串用不同的结构体表示。

    【embstr VS raw】
    长度特别短时,使用embstr形式存储,而长度超过44个字节时,使用raw形式存储。

    要解释为什么长度超过44个字节就要变换存储形式,我们要了解这两种存储形式的真正面貌。
    先来看Redis对象头,这个对象头是所有的Redis对象都会有的结构,这个结构也是会占用空间的:

    struct RedisObject{
    int4 type; //4bits
    int4 encoding; //4bits
    int24 lru; //24bits
    int32 refcount; //4bytes
    void *ptr; //8bytes, 64-bit system
    } robj;

    不同对象具有不同的类型type(4bit)。同一个类型的type会有不同的存储形式encoding(4bit)。为了记录对象的LRU信息,使用了24个bit来记录信息。每个对象都有个引用计数,当引用计数为零时,对象就会被销毁,内存被回收。ptr指针将指向对象内容(body)的具体存储位置。这样一个RedisObject对象头结构需要占据16个字节的存储空间。
    而SDS结构体(body)中,算capacity和len的类型为byte,flags类型也为byte所以就算byte[] content为0,最少也是3个字节,所以和对象头加起来最小空间占用为19个字节。
    内存分配器jemalloc,tcmalloc等分配内存大小的单位是2的幂次方,所以为了能够容纳一个完整的最小embstr结构,最少分配32个字节。如果字符串稍微长一点,就是64个字节。整体超过64个字节,Redis就会认为这是一个大字符串,即使用raw结构存储。
    而64个字节,除开头结构加body中的信息记录字段19个字节,另外content字符串数组的结尾必须为NULL占用1个字节,所以embstr结构中最多能够容纳44个字节的字符串。结构如图:

    【参考】

    《Redis深度历险 核心原理与应用实践》

  • 相关阅读:
    Maven版本管理
    ArrayList集合实现RandomAccess接口有何作用?为何LinkedList集合却没实现这接口
    java常用集合框架关系
    重写equals和hashCode
    项目的继承和聚合详解
    Installation Manager1.8安装
    关于java按位操作运算
    正数负数的二进制表示
    springboot问题排解
    int和Integer有什么区别
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/15800019.html
Copyright © 2011-2022 走看看