咱們知道,在C字符串中,底層的實現是使用c字符數組來實現的,可是在高性能以及內存安全方面,使用底層的c字符串是知足不了的,舉個簡單的例子,若是你使用strcat(s,s1)函數,若是在操做以前不判斷s的空間是否可以容納s1的內容,那麼就頗有可能致使內存溢出,而致使操做失敗,所以,爲了知足性能及內存安全方面的要求,Redis實現了SDS。 數組
SDS的定義是(位於sds.h): 安全
struct sdshdr {
// buf 中已佔用空間的長度
int len; 函數
// buf 中剩餘可用空間的長度
int free; 性能
// 數據空間,默認是使用C字符串的空字符結尾的
char buf[];
}; 優化
其中每項的含義已經在註釋中說明。 設計
經過上面的定義,咱們能夠看到,sds與傳統的c字符串作了幾方面的優化: 內存
在sds中,記錄了「字符數組」的的長度len; 字符串
經過使用free能夠實現預分配策略優化。 擴展
經過這兩方面的優化,咱們能夠獲得如下方面的提高: 程序
在作須要設計到內存擴展方面的操做的時候,只要檢查free屬性,就能夠很容易獲得是否須要擴展內存,從而避免內存溢出;
在獲取字符串長度方面,不再用花費O(N)時間複雜度,只主要得到len屬性就能夠獲得長度,時間複雜度變爲O(1);
咱們知道,C字符串和底層數組之間是有密切聯繫的,所以每次增長或者縮短一個C字符串,都會涉及到對內存的分配,可是使用sds的len屬性和free屬性,能夠減小內存的重分配次數。
關於上面提到的減小內存重分配優化方面,Redis作了兩方面的優化,一個是空間預分配和惰性空間釋放。
空間預分配:這方面的優化主要是用於字符串的增加操做:當用SDS的API來修改一個SDS,且須要進行空間擴展的時候,程序首先會爲SDS分配修改所必須的空間,其次,還會分配額外的使用空間,這裏面有兩個策略:
當對SDS的內存進行修改後,SDS的長度已經超過1M了,那麼Redis會自動的爲這個SDS分配1M的free看空間;
當對SDS的內存進行修改後,SDS的長度小於1M,那麼,Redis會自動給這個SDS分配等同於len的free空間。
惰性空間釋放:對於傳統的C字符串,若是咱們要縮短,那麼就必定要釋放對應的內存,不然會致使內存泄露,可是Redis中的SDS,會把這部份內存用free來記住,因此,能夠不用立刻釋放,這部份內存能夠供之後使用,固然,Redis也提供了相關釋放的API。
此外,咱們對於傳統的C字符串,咱們只能存儲簡單的文本字符串,爲何呢?由於在傳統的字符串中,咱們是使用空字符來判斷這個字符串是否是結束了,所以在字符串的中間就不能使用特殊的字符。這給要在多場景應用下的Redis帶來了弊端,所以,在Redis的SDS中,並非用簡單的空字符來判斷一個buf是否是已經結束了,而是要使用len屬性來判斷是否是已經結束,所以,在Redis的SDS中的buf 是能夠存儲文本字符串以外的數據的,所以,在Redis的SDS中,buf更多的是稱做一個字節數組。固然,SDS中的buf 也是使用空字符來做爲這個串的結尾的,這是爲了兼容一部分C字符串的操做函數。