[ redis ] 底層學習 -- 字符串

知識點

[注] 相關源碼保存位置:src/redis.h、src/sds.h、src/sds.c。

  • 在 redis 中字符串叫 SDS(Simple Dynamic String,動態字符串)

  • SDS 結構如下 – 是一個帶長度信息的字節數組。

    struct SDS<T> {
      T capacity; // 數組容量,1byte
      T len; 	  // 數組長度,1byte
      byte flags; // 特殊標識位,1byte
      byte[] content; // 數組內容
    }
    
  • 字符串存儲方式分爲

    • embstr 長度 44byte 及以下
    • raw 長度 45byte 及以上
  • embstr 最大長度爲 44byte 的原因如下

    • 所有的 Redis 對象都有下面的這個結構頭,此結構佔據 16byte 的存儲空間
      struct RedisObject {
          int4 type;        // 4bits
          int4 encoding;    // 4bits
          int24 lru;        // 24bits
          int32 refcount;   // 4bytes
          void *ptr;        // 8bytes,64-bit system
      } robj;
      
    • 此外 SDS 結構體至少要佔用3byte的空間,所以分配一個字符串的最小空間佔用爲 19byte (16+3)
    • 內存分配器 jemalloc/tcmalloc 等分配內存大小的單位都是 2、4、8、16、32、64 等等,爲了能容納一個完整的 embstr 對象,jemalloc 最少會分配 32byte 的空間,如果字符串再稍微長一點,那就是 64byte 的空間。如果總體超出了 64byte,Redis 認爲它是一個大字符串,不再使用 emdstr 形式存儲,而該用 raw 形式。
    • SDS 結構體中的 content 中的字符串是以字節 \0 結尾的字符串,之所以多出這樣一個字節,是爲了便於直接使用 glibc 的字符串處理函數,以及爲了便於字符串的調試打印輸出。

    所以 embstr 最大能容納的字符串長度就是 44byte (64-16-3-1)。

擴容策略

  • 字符串在長度小於 1M 之前,擴容空間採用加倍策略,也就是保留 100% 的冗餘空間。
  • 當長度超過 1M 之後,爲了避免加倍後的冗餘空間過大而導致浪費,每次擴容只會多分配 1M 大小的冗餘空間。

SDS API

函數 作用 時間複雜度
sdsnew 創建一個給定包含C字符串的SDS O(N),N爲給定C字符串的長度
sdsempty 創建一個不包含任何內容的空 SDS O(1)
sdsfree 釋放給定的SDS O(N),N爲被釋放的SDS的長度
sdslen 返回SDS已使用的字節數 可以直接去讀取SDS的len屬性 O(1)
sdsavail 返回SDS未使用的字節數 可以直接去讀取SDS的free屬性 O(1)
sdsdup 創建一個給定SDS的副本(copy) O(N),N爲給定SDS的長度
sdsclear 清空給定的SDS字符串內容 使用惰性空間釋放策略 O(1)
sdscat 將給定的C字符串拼接到SDS字符串的末尾 O(N),N爲拼接C字符串的長度
sdscatsds 將給定的SDS字符串拼接到另一個SDS字符串的末尾 O(N),N爲拼接SDS字符串的長度
sdscpy 將給定的C字符串複製到SDS中,覆蓋原來SDS中的字符串 O(N),N爲被複制C字符串的長度
sdsgrowzero 用空字符串將SDS擴展到指定的長度 O(N),N被擴展的新增字節數
sdsrange 保留SDS給定區域的數據,不在區域的數據覆蓋或者清除 O(N),N被保留的字節數
sdstrim 接受一個SDS和C字符串的參數,從SDS中移除所有在C字符串中出現過的字符 O(N*N),N爲給定C字符串的長度
sdscmp 對比兩個SDS是否相等 O(N),N兩個SDS中len較小的值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章