• 《Redis设计与实现》阅读笔记(二)--简单动态字符串


    简单动态字符串

    Redis只在一些无需对字符串进行修改的地方使用C字符串,大部分时候使用简单动态字符串simple dynamic string, SDS),字符串的抽象类型。二进制安全,可以存放任意格式的数据。

    定义

     1 源码(部分):
     2 struct __attribute__ ((__packed__)) sdshdr5 {
     3     unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
     4     char buf[];
     5 };
     6 struct __attribute__ ((__packed__)) sdshdr8 {
     7     uint8_t len; /* used */
     8     uint8_t alloc; /* excluding the header and null terminator */
     9     unsigned char flags; /* 3 lsb of type, 5 unused bits */
    10     char buf[];
    11 };
    12 书中代码:
    13 struct sdshdr {
    14     int len;
    15     int free;
    16     char buf[];
    17 }

    这里以书中代码为基础,len为使用的字节数,free表示已分配但未使用的字节数。buf就是char型数组保存字符串。

    这里需要注意的是SDS保存的字符串沿用C字符串的格式,会在最末尾加一个''表示字符串结束,好处是可以复用C语言的函数库。

    举个例子:“hello” len为5,如果free为0,那么这个字符串一共使用6字节,''额外使用一个字节。

    由定义我们可以了解到,SDS的长度可以O(1)获得,而且他使用的内存不是长度+1。而且具有二进制安全的性质。

    空间分配策略

    Redis为了减少内存分配的次数,采用了空间预分配惰性空间释放两种策略。

    空间预分配

    当需要对SDS进行空间扩展的时候,SDS不仅会分配修改所必须的空间,还会进行预分配。

    如果修改后的len值小于1M,那么就会预分配和len同样大小的预留空间。也就是说经过修改和预分配len和free的值是相等的。这时候占有的字节数就是len+free+1。

    而如果修改后的len值大于等于1M,那么就只预分配1M空间。

    惰性空间释放

    当API需要缩短SDS保存的字符串,并不会立即释放多出来的字节,而是使用free记录下来。这样避免了内存重分配的操作,并为将来可能的增长提供了优化。

    如果确实需要释放未使用的空间,SDS也提供了相应的API。

    优点总结

    • 常数时间复杂度获取字符串长度
    • 杜绝缓冲区溢出
    • 减少在修改字符串长度时内存分配的次数
    • 二进制安全
    • 兼容部分C字符串函数
  • 相关阅读:
    【Java】Java 序列化的高级认识
    【随笔】感同身受
    【教训】徐小平:不要用兄弟情谊来追求共同利益,要用共同利益追求兄弟情谊
    【面试】惠普IT电面
    【面试】中兴
    【面试】国金证券
    【298】◀▶ IDL 系统过程&函数
    【297】IDL 过程、函数&关键字参数
    【296】Python 默认 IDE 修改
    【295】暗黑表格模板及相关
  • 原文地址:https://www.cnblogs.com/Star-Dust-/p/10331765.html
Copyright © 2020-2023  润新知