Redis學習筆記 簡單動態字串SDS

2021-09-25 17:07:30 字數 3515 閱讀 4555

引言

redis在我日常工作中使用的頻率相當高,每個專案基本都會用到。在redis的使用過程中,字串使用的頻率也是相當的高,所以有必要學習redis的字串的相關知識。文中涉及的**為redis3.0版本

簡單了解sds(****** dynamic string 簡單動態字串)

redis使用sds進行字串的表示,沒有使用c預設的char*型別,char*的功能單一,抽象層次低,不能高效的支援一些redis的常用操作,如追加和長度計算

sds資料結構

struct sdshdr 

;

sds示例

free:0,表示sds沒有未使用空間

len:5,表示儲存的字串長度是5

buf:char資料,儲存了r、e、d、i、s,buf其實儲存了5個內容字元,還有乙個\0結束字元,

但是\0不會被記錄長度到len當中

4.結束符疑問為什麼還要浪費1個位元組空間去記錄乙個\0結束字元呢?因為c字串是以空字元\0結尾的,sds遵循c 字串以空字元結尾的慣例,並且不會把\0記錄到len的長度當中,在分配空間時會額為分配1個位元組去記錄該字元,整個的操作都是sds的函式自動完成的,使用者無需關心。

使用空字元\0結尾的好處是,可以使用c字串函式庫裡面的函式

sds和c字串

3.1.c字串

c字串的結構如上所示,c字串不能滿足redis對字串的安全性、效率以及功能方面的需求,所以redis才會使用sds

3.2.c字串的問題

獲取字串長度,獲取乙個c字串的長度,程式必須遍歷整個字串,直到遇到結尾的空字元\0為止,時間複雜度為o(n)

*strcat

(char

*dest,

const

char

*src)

;執行:

strcat

(s1,

" cluster");

記憶體頻繁分配和**記憶體,當對字串頻繁的修改時,c字串需要頻繁的分配和**記憶體。

二進位制安全,c 字串中的字元必須符合某種編碼(比如 ascii), 並且除了字串的末尾之外, 字串裡面不能包含空字元, 否則最先被程式讀入的空字元將被誤認為是字串結尾。舉個栗子:

上圖的字串使用了空字元分隔,此時c字串所用的函式只能識別其中的 「reids」,會忽略後面的"cluster"

3.3sds如何解決這些問題

獲取字串的長度,在sds的結構體當中使用了len屬性記錄字串內容的長度,sds獲取長度的**如下:

/*

* 返回 sds 實際儲存的字串的長度

* * t = o(1)

*/static

inline size_t sdslen

(const sds s)

杜絕記憶體溢位,當 sds api 需要對 sds 進行修改時, api會先檢查 sds的空間是否滿足修改所需的要求, 如果不滿足的話, api會自動將 sds 的空間擴充套件至執行修改所需的大小, 然後才執行實際的修改操作。

減少修改字串時帶來的記憶體分配次數,c字串修改字串需要重新分配記憶體,否則會導致記憶體溢位,sds採取空間預分配惰性空間釋放方法從而較少記憶體分配次數

空間預分配:

sds api對sds修改時,如果此時需要對sds的空間進行擴充套件,sds不僅會分配當前操作所需要的空間,還會為sds分配額外的未使用空間,這樣redis在後續執行字串增長操作到時候可以減少記憶體重新分配的次數。

對sds修改後,如果len小於1m,則程式分配的和len相同的大小未使用空間,也就說此時len和free值是相等的。舉個栗子:對sds的修改,sds的len變成了13位元組,程式會分配13位元組的未使用空間,則sds的buf陣列的實際長度為13+13+1 = 27位元組,即len+free+空字元=27位元組

對sds修改後,如果len大於1mb,則程式會分配1mb的未使用空間,舉個栗子:sds修改後為3mb,那麼程式會分配1mb的未使用空間,則buf陣列的實際長度為3mb+1mb+1byte

通過這種預分配策略,sds 將連續增長 n 次字串所需的記憶體重分配次數必定 n 次降低為最多 n 次。(因為free的空間有可能不滿足當前修改操作的所需空,所以是降低為最多n次)

惰性空間釋放:

sds的api對sds的縮短操作時,程式不會立即**記憶體,而是使用free屬性將這些需要**位元組的數量記錄起來,等待將來使用。字串」xyxxyabcxyy」移除所有的「x」和「y」,過程如下圖所示。

如上圖所示,sds並沒有釋放多出來的 8 位元組空間, 而是將這 8 位元組空間作為未使用空間保留在了 sds裡面, 如果將來要對 sds進行增長操作的話, 這些未使用空間就可能會派上用場

二進位制安全,sds的api都是二進位制安全的,所有 sds api 都會以處理二進位制的方式來處理 sds 存放在 buf 陣列裡的資料, 程式不會對其中的資料做任何限制、過濾、或者假設 —— 資料在寫入時是什麼樣的, 它被讀取時就是什麼樣。

總結

sds比起c字串有以下優點:

常數複雜度獲取字串長度

杜絕緩衝區溢位

減少修改字串長度時所需的記憶體重分配次數

二進位制安全

相容部分 c 字串函式

參考資料

<

redis 學習筆記二 簡單動態字串

一 c語言動態陣列 先看下一般的動態陣列結構1 2 3 4 5 structmydata 這是個廣泛使用的常見技巧,常用來構成緩衝區。比起指標,用空陣列有這樣的優勢 1.不需要初始化,陣列名直接就是所在的偏移 2.不佔任何空間,指標需要占用int長度空間,空陣列不佔任何空間。這個陣列不占用任何記憶體...

Redis 簡單動態字串

在c語言中,乙個結構體中最後乙個成員的位址減去第乙個成員的位址,就是該結構體的大小 例如 struct sdshdr buf的位址減去len的位址,正好等於sizeof sdshdr 在c 中 char str nihao 是不被允許的,但是c語言中可以,並且可以直接列印str 輸出nihao,和c...

redis簡單動態字串

redis內部使用sds,簡單動態字串,sds是什麼 dynamic t包含字串長度,空間使用率,已使用,未使用等資訊的乙個結構體 sds比c語言字串的優點 獲取字串長度不需要進行遍歷,時間複雜度為o 1 杜絕緩衝區溢位 對sds進行修改的時候,api會先檢查sds的空間是否足夠,如果不需要的話,a...