本篇實際上對博客園大佬【酷酷的洛克】的教程的細分講解,原文鏈接:NavicatPremium16破解 使用Windows系統的同學第一步是先關掉系統安全防護,不然破解工具會被視為病毒,OS自動就給你刪掉了。關閉方法請參考此文:臨時關閉Windows安全中心 之後按照正常流程先將Navicat_Pre ...
1.SDS介紹(為什麼要提出SDS)
無論是Redis的key還是Value,其基礎數據類型都是字元串。例如,Hash型Value的field 與 Value的類型、List型、Set型、ZSet型Value的元素都是字元串。雖然Redis是使用標準C語言開發的,但並沒有直接使用C語言中傳統的字元串表示,而是自定義了一種字元串。這種字元串本身的結構比較簡單,但功能卻非常強大,稱為簡單動態字元串,Simple Dynamic String,簡稱SDS。
註意:Redis中的所有字元串並不都是SDS,也會出現C字元串。C字元串只會出現在字元串“字面常量”中,並且該字元串不可能發生變更。例如,Redis 返回的結果中包含的字元串就是C語言的字元串。
2.SDS結構
SDS 不同於C字元串。C字元串本身是一個以雙引號括起來,以空字元串‘\0’結尾的字元串序列。但SDS是一個結構體,定義在Redis安裝目錄下的 src/sds.h中。
struct sdshdr { //位元組數組,用於保存字元串 char buf[]; //buf[]中已使用位元組數量,稱為SDS的長度 int len; //buf[]中尚未使用的位元組數量 int free; }
例如執行 set countey "China" 命令時,鍵country 與值 ”China“ 都是SDS類型的,只不過一個是SDS的變數,一個是SDS的字面常量,”China“在記憶體中的結構如下:
通過以上結構可以看出來,SDS的buf值實際上是一個C字元串,包含空字元串‘\0’共占6個位元組。但SDS的len是不包含‘\0’的。
在實際的使用過程中,經常會做一些預分配,變成下麵這種結構。
該結構與前面不同的是,這裡面有3位元組未使用空間。
補充
type keyname
可以查看那種類型。
object encoding keyname
可以查看key對應的value在記憶體中的存儲類型。例如,如果返回的是"embstr",就是我們前面說的SDS。
3.SDS的優勢
C字元串使用len+1長度的字元串數組來表示實際長度為len的字元串,字元串數組最後以空字元串’\0‘結尾,表示字元串結尾。這種結構簡單,但不能滿足Redis對字元串功能性、安全性及高效性等的要求。
(1)防止“字元串長度獲取”的性能瓶頸
對於C字元串,若要獲取其長度,則必須要通過遍歷整個字元串才能獲取得到。對於超長字元串的遍歷,會成為系統的性能瓶頸。而由於SDS結構體中直接就存放著字元串的長度數據,所以對於獲取字元串長度需要消耗的系統性能,特別是在長字元串的情況下,不會成為Redis的性能瓶頸。
(2)保障二進位的安全
C字元串中只能包含符合某種編碼格式的字元,例如ASCII、UTF-8等,並且除了字元串尾外,其他位置是不能包含空字元串’\0‘的,否則該字元串就會被程式誤解為提前結束,而在圖片、音頻、視頻、壓縮文件、office 文件等二進位數據中常以空字元串'\0'作為分隔符的情況是很常見的,故而在C字元串中是不能保存圖片、音頻、視頻、壓縮文件、office 文件等二進位數據的。
但SDS不是以空字元串'\0'作為結束標誌的,其是通過len屬性來判斷字元串是否結束的。所以,對於程式處理SDS中的字元串數據,無需對數據做任何限制、過濾、假設,只需讀取即可。數據寫入的是什麼,讀到的就是什麼。
(3)減少記憶體再分配次數
SDS採用了空間預分配策略與惰性空間釋放策略來避免記憶體再分配問題。
空間預分配策略是指,每次SDS進行空間擴展時,程式不但為其分配所需的空間,還會為其分配額外的未使用空間,以減少記憶體再分配次數。而額外分配的未使用空間大小取決於空間擴展後SDS的len屬性值。
***如果len屬性值小於1M,那麼分配的未使用空間free的大小與len相同。
***如果len的屬性值大於等於1M,那麼分配的未使用空間free的大小就是1M。
SDS對於空間釋放採用的時惰性空間釋放策略。該策略是指,SDS字元串長度如果縮短,那麼多出的未使用空間將暫時不釋放,而是增加到free中。所以後期擴展SDS時減少記憶體再次分配。
如果要釋放SDS的未使用空間,則可以通過sdsRemoveFreeSpace()函數來釋放。
(4)相容C函數
Redis中提供了很多SDS的API,以方便用戶對SDS進行二次開發。為了能夠相容C函數,SDS的底層數組buf[]中的字元串仍以空字元串'\0'結尾。
4 常用的SDS操作函數
函數 | 功能描述 |
sdsnew() | 使用指定的C字元串創建一個SDS |
sdsempty(); | 創建一個不包含任何字元串數據的SDS |
sdsdup(const sds s); | 複製字元串(創建一個指定SDS的副本) |
sdsfree() | 釋放指定的SDS |
sdsclear() | 清空指定SDS的字元串內容 |
sdslen() | 獲取指定SDS的已使用空間len值 |
sdssaveall() | 獲取指定SDS的未使用空間free值 |
sdsMakeRoomFor() | 使指定的SDS的free空間增加指定的大小 |
sdsRemoveFreeSpace() | 釋放指定SDS的free空間 |
sdscat() | 將指定的C字元串拼接到指定SDS字元串末尾 |
sdscatsds() | 將指定的SDS的字元串拼接到另一個指定的SDS字元串末尾 |
sdscpy() | 將指定的C字元串賦值到指定的SDS中,覆蓋原SDS字元串內容 |
sdsgrowzero(sds s, size_t len); | 擴展SDS字元串到指定長度,這個擴展是使用空字元串’\0‘填充 |
sdsrange(sds s, int start, int end) | 截取指定SDS中指定範圍內的字元串 |
sdstrim(sds s, const char *cset); | 在指定SDS中刪除所有隻當C字元串中出現的所有字元 |
sdsemp() | 對比兩個給定SDS字元串是否相同 |
sdstolow() | 將指定SDS字元串中的所有字面變為小寫 |
sdstouper() | 將指定SDS字元串中的所有字面變為大寫 |
學習參閱聲明
【Redis視頻從入門到高級】
https://www.bilibili.com/video/BV1U24y1y7jF?p=11&vd_source=0e347fbc6c2b049143afaa5a15abfc1c】