SDS(simple dynamic string)
,簡單動態字符串。s同時它被稱爲 Hacking String。hack 的地方就在 sds 保存了字符串的長度以及剩餘空間。sds 的實如今 sds.c
中。javascript
C語言字符串使用長度爲n+1的字符數組來表示長度爲n的字符串,而且字符數組的最後一個元素老是空字符'\0',這樣的方式存儲,時存在安全隱患的,而且它不能知足效率方面的需求。java
所以Redis沒有使用C原生的string
而是本身構建了SDS
。在Redis裏,C語言字符串只用於一些無須對字符串值進行修改的地方,好比:日誌。算法
在Redis中,包含字符串值的鍵值對都是使用SDS實現的,除此以外,SDS還被用於AOF緩衝區、客戶端狀態的輸入緩衝區。數組
struct sdshdr{ //字節數組 char buf[]; //buf數組中已使用字節數量 int len; //buf數組中未使用字節數量 int free; }
如上圖所示,len表示該SDS保存了一個6字節長度(不包含結束符)的字符串,free表示該SDS還有6個字節的未使用空間,buf是一個char類型的數組
,保存了該SDS所存儲的字符串值。安全
相比C語言字符串,使獲取字符串長度時間複雜度降爲O(1)
而C原生的獲取長度爲O(N)
遍歷整個數組。性能
同時SDS
杜絕緩衝區溢出,不會像C那樣形成數組數據不安全,絕對不會越界。優化
當須要對SDS進行修改時,API會先檢查SDS當前剩餘空間是否知足修改以後所需的空間,若是不知足的話API會自動將SDS的空間擴展至足夠用的空間而後才進行下一步操做,因此SDS不會出現緩衝區溢出問題。日誌
C語言字原生符串底層是使用一個n+1個字符長度的char類型數據實現的,因此每次增加或縮短一個原生字符串,程序都要對這個字符串數組進行一次內存重分配操做:code
同時由於內存重分配涉及複雜的算法,而且可能須要執行系統調用,因此它一般是一個比較耗時的操做。Redis常常被用於速度要求嚴苛、數據被頻繁修改的場合,若是每次修改字符串都須要執行一次內存重分配的話,那麼對於性能會形成很大影響。blog
SDS 在分配了內存以後(每每空間會存在盈餘,也就是空間的預分配),而後本身經過len 和 free 來維護已使用的和未使用的內存,再也不依賴系統來從新劃分,這樣能有效的提高性能。
用於字符串增加操做,當字符串增加時,程序會先檢查需不須要對SDS空間進行擴展,若是須要擴展,程序不只會爲SDS分配修改所必要的空間,還會爲SDS分配額外的未使用空間,額外分配的未使用空間公式以下:
SDS空間 < 1MB
若是對SDS修改以後,SDS的長度(修改以後len屬性的值)小於1MB,那麼則分配和len屬性一樣大小的未使用空間,這時SDS的len屬性和free屬性的值相同。如:若是修改以後SDS的len將變爲10字節,那麼程序也會分配10字節的未使用空間,SDS的buf數組實際長度變爲10 + 10 + 1 = 21(額外一個字節用於保存結束符\n)
SDS空間 > 1MB
若是對SDS修改以後,SDS的長度大於等於1MB,那麼程序會分配1MB的未使用空間。如:修改以後的len將變爲10MB,那麼程序會分配1MB的未使用空間,SDS的bug數組長度爲10MB + 1MB + 1byte
SDS空間 > 512MB
Game over~ 報錯!
用於優化SDS的字符串收縮操做,當字符串收縮時,程序不會當即執行內存重分配來回收收縮後內存多出來的空間,而是使用free屬性記錄下來,以備未來使用。
經過空間預分配,Redis能夠減小連續執行字符串增加操做所需的內存重分配次數,經過惰性空間釋放,SDS避免了縮短字符串時所需的內存重分配操做,併爲未來由可能的增加操做提供了優化。