struct sdsher;
說明:sds為了能夠使用部分c字串函式,遵循了c字串以空字元結尾的慣例,儲存空字元的1位元組不計算在sdslen屬性中,並且為空字元分配額外的1位元組空間,以及新增空字元到字串末尾等操作,都是由sds函式自動完成的,可以說空字元對使用者是不可見的!
**c語言中實現字串長度計數的複雜度為o(n)。
而反觀sds中,因為其結構中儲存了len這一屬性,所以獲取sds長度的複雜度僅為o(1)。
並且我們不需要手動修改len屬性,設定和更新sds長度的工作是由sds的api在執行時自動完成的。
c語言由於不記錄自身長度,所以又帶來乙個問題:容易造成緩衝區溢位(buffer overflow)。
舉個栗子!當我們擁有兩個c字串s1,s2。而恰好s1、s2的記憶體是緊挨著的,那麼當對s1執行某些操作,例如字串拼接函式strcat(char* dest,char* src),那麼毫無疑問,s2的資料會被覆蓋掉!這樣就造成了資料的丟失!
示意圖:
執行strcat(s1,「dlrow」);
所以,sds與c字串不同,由於其記錄了長度,所以在api需要對sds進行修改時,api會先檢查sds的空間是否滿足修改所需要的空間,如果不滿足,api會自動將sds的空間擴充套件至執行修改所需的大小,然後才執行操作,因此避免了緩衝區溢位的問題!
依舊以上述例子為例:
當sds執行 sdscat(s1,「dlrow」)時,首先檢測到長度是否滿足:
不滿足,於是去拓展空間:
注意此處又為sds分配了10位元組未使用空間,並且拼接後的字串也是10!this is not a coincidence!它與sds的空間分配策略有關!
而因為記憶體重分配設計複雜的演算法,甚至可能需要執行系統呼叫,所以它通常是乙個比較耗時的操作:
對於一般程式而言,對於修改字串的長度的情況可能不太頻繁,所以每次修改都執行一次記憶體重分配也還是可以接受的。
但是redis作為資料庫,經常被用於速度要求嚴苛、資料被頻繁修改的場合,那麼顯然,如果每次都要執行一次記憶體重分配,開銷簡直驚為天人!
所以sds對於這種情況的處理是:sds的free屬性!
sds通過未使用空間解除了字串長度和底層陣列長度之間的關聯:在sds中,buf陣列的長度不一定就是儲存的字元長度加一(這個在之前的結構體中可以看出),陣列裡可以包含未使用的位元組,而這些位元組的數量就由sds的free屬性記錄。
通過free屬性(未使用空間),sds實現了空間預分配和惰性空間釋放兩種優化策略!
(1)空間預分配
空間預分配用於優化sds的字串增長操作:當sds的api對乙個sds進行修改,並且需要對sds進行空間拓展時,程式不僅為sds分配修改所需要的空間,還會為sds分配額外的未使用空間,這與cache中的一些演算法思想相類似,都是認為最近使用過的資料可能會被再次訪問或者修改,於是便給其乙個預留的未使用空間!
分配原則一般如下:
如果對sds進行修改之後,sds的長度(也就是len屬性的值)將小於1mb,那麼程式分配和len屬性同樣大小的未使用空間。反之,如果sds的長度將大於1mb,那麼程式會分配1mb的未使用空間。
(但是值得注意的是,sds總佔位元組數 = len + free + 1,1是末尾空字元)
顯然,通過使用空間預分配是可以有效減少記憶體重分配次數的。
如果不採用此預分配策略,當sds需要連續增長n次時,記憶體重分配為n次,而應用此策略,則變成了最多n次!
(2)惰性空間釋放
同(1)所述,當面對字串縮短操作:如果沒有特殊操作,sds的api需要縮短sds儲存的字串,那麼就需要使用記憶體重分配來**多餘的位元組。
而當我們有了free屬性,可以將多餘位元組調配給free記錄下來,並等待將來使用!這也就為將來可能存在的增長操作提供了優化!
內容參考自《redis設計與實現》
SDS產品如此成功的原因何在?
軟體定義的儲存方法涉及許多移動部件,包括超融合系統 用於快速資料傳輸的網路和固態驅動器。軟體定義儲存仍處於發展的早期階段。許多產品不能滿足軟體定義儲存方法的目標,儘管它們仍然這仍然是有價值的進步 而且,隨著軟體 商的擴充套件和互操作性變得更重要,它將產生更多未來的問題。讓我們實現軟體定義儲存 sds...
redis資料結構 SDS
在使用中,redis有五種物件 string hash list set sorted set 在redis中有以下幾種資料結構 sds 鍊錶 字典 跳躍表 整數集合 壓縮列表,它們在不同的條件下實現了redis的五種物件。先來看sds的結構 在sds.h中定義了幾種不同的結構用來存放不同型別的資料...
redis資料結構 SDS
sds結構體組成 struct sdshdr sds相比普通字串的好處 redis 只會使用c字串作為字面量,在大多數情況下,redis 使用sds dynamic string,簡單動態字串 作為字串表示。比起 c 字串,sds 具有以下優點 常數複雜度獲取字串長度。杜絕緩衝區溢位。減少修改字串長...