Redis字串表示 SDS總結

2021-10-05 19:33:29 字數 2380 閱讀 2333

目錄

1.sds的結構

2.sds與c語言的區別

1.獲取字串長度的複雜度為常數。

2.對字串執行修改不會造成緩衝區溢位。

3.字串修改造成的記憶體重分配次數減少。

4.sds字串二進位制安全。

5.相容部分c字串函式。

redis雖然使用c語言編寫,但其字串表示並沒有直接使用傳統的c字串表示(以空字元結尾的字元陣列),而是使用了一種新的字串表示--sds,即簡單動態字串。c字串僅作為字串的字面量用於無需對字串值進行修改的地方,如日誌列印。

sds可以用來儲存資料中字串的值,也可以用來作為緩衝區:aof模組中的aof緩衝區,以及客戶端狀態中的輸入緩衝區都是由sds實現。

為了節省記憶體,從redis3.2開始,sds就有了5種字串頭結構型別,分別為:sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64,這5種型別分別存放不同大小的字串。其中sdshdr5與其他幾個header結構體不同,不包含alloc屬性,而是用flags的高5位來儲存。因此不能為字串分配空餘空間。另外4種字串頭結構包含的屬性一樣,以sdshdr8為例,如下:

struct __attribute__ ((__packed__)) sdshdr8 ;
__attribute__ ((packed))這個命令的作用是取消編譯階段的記憶體優化對齊功能,按照結構體中各個元素實際占用的位元組數進行對齊。使用__attribute__ ((packed))之後,sdshdr(8,16,32,64)中各個元素是緊緊相鄰的。

使用__attribute__ ((packed))有兩點好處:

1.redis一般作為記憶體資料庫使用,__attribute__ ((packed))屬性能夠盡最大的可能節約記憶體空間,從而增加記憶體中可以存放的鍵值對的數量,提高系統的效能。      

2.__attribute__ ((packed))屬性使得所有的元素在記憶體中的位置可以按照簡單的加減進行計算,因此可以根據指定的sds的位置,確定flag的位置;例如給定sds為s,那麼flag的位置就是s[-1],即結構體的型別,這使得結構體內部定址變得簡單。redis原始碼中都是以這種方式取的結構體的型別。

在各個頭結構的定義中最後有乙個char buf。這是乙個沒有指明長度的字元陣列,這是c語言中定義字元陣列的一種特殊寫法,稱為柔性陣列(flexible array member),只能定義在乙個結構體的最後乙個欄位上。它在這裡只是起到乙個標記的作用,表示在flags欄位後面就是乙個字元陣列,或者說,它指明了緊跟在flags欄位後面的這個字元陣列在結構體中的偏移位置。而程式在為header分配的記憶體時,它並不占用記憶體空間。如果計算sizeof(struct sdshdr16)的值,那麼結果是5個位元組,其中沒有buf欄位。所以sds的結構類似於如下的形式:

在建立字串時,sds會根據字串的長度選擇不同的頭結構型別。最終由sdsnewlen函式建立字串。                                        

主要區別有5點:

由於c字串不記錄自身長度資訊,其獲取長度的操作複雜度為o(n),而sds在len屬性中記錄sds長度,獲取長度的複雜度僅為o(1)。

c字串如果沒有分配足夠的空間,在拼接時容易造成資料溢位。sds在拼接時,如果空間不足,會根據空間分配策略對sds的空間自動擴充套件。

c字串的修改每次都需要進行記憶體重分配。sds中通過未使用的空間實現了空間預分配和惰性空間釋放兩種優化策略。

(1)空間預分配:用於優化sds字串增長操作。當對sds進行修改時,如果需要進行空間擴充套件,除了為sds分配必須要的空間,還會為sds分配額外的未使用空間。原始碼如下:

sds sdsmakeroomfor(sds s, size_t addlen)  else 

sdssetalloc(s, newlen);

return s;

}

(2)惰性空間釋放:用於優化sds字串縮短操作。當需要縮短sds儲存的字串時,並不立即將縮短後多出的位元組進行**,而是等待將來使用,見sdstrim函式。若將來有字串增長的操作,就可以減少記憶體重分配次數。在有需要時,sdsremovefreespace函式可以真正釋放sds未使用的空間。

c字串除字串末尾外,字串裡不能包含空字元,否則最先的空字元會被誤認為是字串結尾,導致c字串不能儲存二進位制資料。而sds的api都會以處理二進位制的方式處理sds中的資料,使得sds不僅可以儲存文字,也可以儲存二進位制資料。

sds遵循c字串空字元結尾的特點,使得sds可以重用部分c字串函式,避免不必要的重複**。

redis的動態字串SDS

redis雖然是用c來實現的,但是他的字元型別並沒有完全採用c的型別,c字串只是字串字面量,只有在用一些不需要變化的字串時才會採用c字串。比如列印日誌,而在使用需要變化的時候使用sds,比如當鍵值對的值是字串時。還被用作緩衝區 至於為什麼這樣做,則是考慮到了redis的應用場景,redis一般被用作...

Redis的底層字串儲存 SDS

我們知道redis資料庫是使用c語言寫的,然而其內部的字串的儲存卻並不是使用傳統的c語言字串表示,而是使用一種名為簡單動態字串 dynamic string,sds 的抽象資料型別。首先我們來對sds有乙個大概的認識 如果我們客戶端執行如下命令 127.0.0.1 6381 set msg hell...

Redis之簡單動態字串 SDS

簡單動態字串sds dynamic string sds資料結構如下 struct sdshdr基於sds資料結構的定義和一些api規則,sds相比於c字串有如下優勢 1.獲取字串長度的複雜度為o 1 c字串的複雜度為o n 2.杜絕緩衝區溢位 3.減少修改字串時帶來的記憶體重分配次數 4.二進位制...