Redis設計與實現系列-基本數據結構-SDC

關於《Redis設計與實現》讀書筆記java

SDC全稱是(simple dynamic string,SDS),Redis是以C語言編寫的,可是Redis並無直接使用C語言內置的字符串(C語言內置的字符串以空格結束),Redis本身構建了一套抽象字符串SDC用來描述Redis中使用的字符串,當且僅當使用字符串常量時Redis纔會直接使用C語言字符串。redis

咱們使用Set命令設置一個鍵值對時,例如SET ls "hello",Redis將會在數據庫中設置一個鍵值對,其中鍵值對的鍵是一個字符串對象,底層實現了一個保存ls的SDC對象;鍵值對的值也是一個字符串對象,底層實現了一個保存"hello"的SDC對象。數據庫

若是咱們使用LPUSH指令設置一個列表,例如 RPUSH fruits "apple" "banana" "cherry",Redis將會在數據庫中設置一個鍵值對,其中鍵值對的鍵也是一個字符串對象,底層實現了一個保存fruits的SDC對象,鍵值對的值是一個列表對象,列表中包含3個字符串,每一個字符串都是一個SDC對象。api

經過兩個例子咱們對SDC有了簡單的認識,簡單地說SDC就是用Redis對C語言字符串的一個封裝,可是這種封裝在Redis中有着嚴格的定義,C語言中沒有類這種概念,C語言中SDC是用一個結構體來描述SDC,具體定義在Redis中sds.h文件中,以下所示:數組

struct sdshdr {

    // 記錄 buf 數組中已使用字節的數量
    // 等於 SDS 所保存字符串的長度
    int len;

    // 記錄 buf 數組中未使用字節的數量
    int free;

    // 字節數組,用於保存字符串
    char buf[];

};

若是瞭解Java的同窗能夠很明白,這種封裝跟Java中的從java.lang.String類封裝相似,顯然len就是維護着字符串的長度,buf是一個char數組,Java中String也有這兩個東西,其中free用於保存buf數據組中未使用的空間也很好理解。緩存

上圖很形象地描述了SDC的定義,SDC跟C語言字符串同樣分配了一字節空間存儲'\0',這樣有一個好處就是能夠直接使用部分C語言字符串函數,例如:printf("%s", s->buf),這樣就無需單獨爲redis設計打印函數了,殊途同歸。安全

C字符串與redis字符串區別app

  • 常數時間複查度獲取字符串長度,C字符串要獲取字符串長度必須遍歷字符串的每個字節直到遇到'\0'字符才能獲取字符串長度,顯然這是一個O(N)時間複雜度,SDC因爲內置的字符串長度變量,所以只須要在常熟時間複查度就能夠直接獲取字符串長度,redis很大一部分是用做緩存使用,每一個地方的性能提高都對總體性能提高很是有用。
  • 杜絕緩衝區溢出,因爲不記錄字符串長度C字符串很容易形成緩衝區溢出,C語言中strcat函數能夠將字符串拼接到某個字符串後面,使用這個函數的假設是目標對象分配了足夠的內存,若是這個假設不成立將會形成緩衝區溢出致使其它內存區域的變量被修改。SDC則不會存在這個問題,SDC每次執行拼接操做時都會檢查當前字符串長度看是否有足夠的剩餘空間,若是空間不夠則對buf數組進行擴容。
  • 下降內存分配次數,C語言字符串每次執行拼接操做若是字符串內存容量不夠都要進行擴容操做,不然將會形成緩衝區溢出;每次執行剪切字符串操做都要釋放不須要使用的內存,不然會形成內存溢出。內存分配和釋放涉及到系統調用是很是損耗系統性能的,redis做爲一場很是苛刻的緩存數據庫常常會用到字符串的長度變換若是每次都執行內存分配和釋放將會給系統帶來很大的壓力。而在SDC中buf數組長度長度不必定就是當前字符串長度,buf內部能夠包含未使用的空間,其中free就描述了未使用的空間大小。經過free SDC實現的空間預分配和惰性釋放。
  • 空間預分配,空間預分配主要用於優化SDC的字符串增加操做,若是當前buff的未使用空間不能知足新的字符串增加須要,SDC不只僅分配新進字符串空間還會分配額外的空間,這樣在下一次拼接字符串時就可能不須要再次分配空間了,必定程度降低低了內存分配次數。
  • 空間惰性釋放,空間惰性釋放主要用於優惠字符串縮短操做,當字符串縮短時並非當即使用內存空間而是使用free記錄,這樣下次要執行拼接操做時可能就不須要進行空間分配了,固然redis也經過API主動對未使用的內存進行釋放。
  • 二進制安全,C字符串必須是某種編碼格式,並且字符串內部不能包含空字符串,不然會被視爲字符串結尾,這就限制了C字符串只能保存文本信息不能保存視頻、圖片等二進制信息,redis的api都是二進制安全的,不只僅能保存文本信息也能夠保存二進制信息,redis api都會以處理二級制信息來處理保存在buf中的信息不會對其進行過濾限制。
  • 兼容部分C字符串函數,好比printf函數(上面提到)。
相關文章
相關標籤/搜索