zoukankan      html  css  js  c++  java
  • redis_字符串对象

    Redis总共支持五种数据类型:string,hash,list,set及zset。这里介绍字符串类型的实现

    首先了解字符串对象的结构

    // redis对象内存分配,列出主要相关的属性
    redisObject {
        // 对于字符串对象,type = REDIS_STRING
        type
        // 字符串的底层编码,有三种:int、raw、embstr,后文介绍
        encoding
        // 指向实际保存字符串内容的空间
        ptr
        // 还有其他属性
        ......
    }

    上面的redisObject不实际保存字符串内容,而是通过ptr指向实际保存字符串内容的空间,叫sdshdr(Simple Dynamic String hdr 简单动态字符串)

    struct sdshdr {
        // 记录buf数组中已使用的字节数,等同于字符串长度(不包括结尾的)
        int len;
        // 记录buf数组中未使用的字节数
        int free;
        // 实际保存字符串的字节数组
        char buf[];
    }

    这个sdshdr比较厉害,在字符串变长的时候可以预申请额外内存、缩短时不直接释放内存以备未来变长使用,等。

    sdshdr的详细看这里:https://www.cnblogs.com/loveCheery/p/9133343.html

    字符串编码

    字符串对象有三种可能的底层编码:int、raw、embstr。

    这三种编码格式是字符串对象底层空间分配的不同,对上层调用没有区别,不同编码的字符串对象在执行命令时效果是一样的

    int编码

    如果字符串保存的值是整数,范围在long之内,那么encoding会被设置为int,并且直接将证书值保存在ptr里(ptr不再指向一个复杂的sds结构了,直接是整数值)

    // 插入long之内的值为整数的字符串
    127.0.0.1:6379> set test "123" 
    OK
    127.0.0.1:6379> object encoding test
    "int"
    // 插入long的最大值2^63-1
    127.0.0.1:6379> set test "9223372036854775807" 
    OK
    127.0.0.1:6379> object encoding test
    "int"
    // 插入2^63,就不是int编码了
    127.0.0.1:6379> set test "9223372036854775808" 
    OK
    127.0.0.1:6379> object encoding test
    "embstr"

    raw编码

    如果字符串保存的值长度比较大,那么encoding为raw,值使用sds(简单动态字符串),ptr指向这个sds的空间

    比较大:《Redis设计与实现》里说长度大于39字节时,n多文章说长度大于32字节时,我测试返回长度大于44时才行,没查到是配置可选的还是redis版本指定的

    总的来说就是对于大字符串,redis采用一套机制来控制字符串变长变短时的内存分配策略,实现是用的sds

    embstr编码

    如果字符串保存的值不是整数,并且长度不是很大那么encoding为embstr,值也是sds,ptr指向这个sds的空间

    embstr编码是专门用于保存段字符串的一种优化编码方式

    • embstr和raw的实际字符串存储都是用了sds,区别在于:
    • embstr编码的字符串对象,其所有数据保存在一块连续的内存空间中(redisObject和其ptr指向的sds在连续的内存空间),只需要一次内存分配操作
    • raw编码的字符串对象,redisObject和其ptr指向的sds是不连续的,需要两次内存分配

    embstr的内存空间连续的优势

    • 其创建时的内存分配、释放时的内存回收次数都只有1次
    • 方便预读取一段空间内的数据做缓存

    其他

    • embstr只读,没有修改方法。当对embstr编码的字符串做修改时,会先转为raw、再修改
    • 127.0.0.1:6379> set test "hello"
      OK
      127.0.0.1:6379> object encoding test
      "embstr"
      127.0.0.1:6379> append test "world"
      (integer) 10
      127.0.0.1:6379> object encoding test
      "raw"
    • int编码在执行append前,也会先转为raw,再修改
    • int编码执行整数计算时(比如incrby)直接使用整数编码
    • raw和embstr编码,执行整数方法(比如incrby)时,如果其内容为long内的整数,则先转为int再执行,执行完还是int。如果内容不是long内的整数,则向客户端抛出异常

    字符串命令详细实现:

     

    micheal.li > 阿智
    micheal.li > mikeve@163.com
  • 相关阅读:
    HDU 2433 Travel (最短路,BFS,变形)
    HDU 2544 最短路 (最短路,spfa)
    HDU 2063 过山车 (最大匹配,匈牙利算法)
    HDU 1150 Machine Schedule (最小覆盖,匈牙利算法)
    290 Word Pattern 单词模式
    289 Game of Life 生命的游戏
    287 Find the Duplicate Number 寻找重复数
    283 Move Zeroes 移动零
    282 Expression Add Operators 给表达式添加运算符
    279 Perfect Squares 完美平方数
  • 原文地址:https://www.cnblogs.com/loveCheery/p/9145191.html
Copyright © 2011-2022 走看看