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
  • 相关阅读:
    面试问题整理Andorid版本 date: 2017-1-12 21:14:36 categories: 技术
    轻量级的C++插件框架
    C++程序在Windows平台上各种定位内存泄漏的方法,并对比了它们的优缺点
    Facebook App 的头文件会有更多的收获
    合并Excel工作薄中成绩表的VBA代码,非常适合教育一线的朋友_python
    使用python在校内发人人网状态(人人网看状态)_python
    使用PYTHON创建XML文档_python
    优秀的缓存请求库,快速请求接口和图片:WTRequestCenter
    让读者快速了解RocketMQ消息中间件需要解决哪些问题
    编绎调试HotSpot JVM及在Eclipse里调试HotSpot一些步骤
  • 原文地址:https://www.cnblogs.com/loveCheery/p/9145191.html
Copyright © 2011-2022 走看看