Redis源碼分析(一)——Redis資料結構-字串SDS,redissds
1. SDS簡介
- Redis中使用的字串均為『簡單動態字串』(Simple Dynamic String),簡稱SDS。
- SDS是在C字串的基礎上進行了一些封裝,使得它更符合Redis的使用情境。
- 在Redis中,C字串只用在一些無需修改的地方,如日誌列印;其他需要使用字串的地方基本上使用的都是SDS。
2. 資料結構
struct sdshdr{ int len; int free; char buf[];};
len
:buf數組中字串的實際使用量。
free
:buf數組中空閑量。
buf
:儲存字元的數組。
3. SDS的優點
Redis使用C語言編寫,而Redis不使用C語言字串是有原因的,Redis中的SDS字串與C字串相比有如下優點。
3.1 擷取字串長度效率高
C語言字串是不記錄字串長度的,所以每次擷取字串長度時,都要對字元數組進行一次遍曆,那麼時間複雜度就為O(n)。
而SDS中採用len記錄當前字串的長度,所以統計字串長度的時間複雜度為O(1),因此效率高於C字串。
3.2 避免了緩衝區溢位3.2.1 什麼是『緩衝區溢位』?
當使用strcat(char *dest, char *src)
拼接兩個字串時,strcat
是預設第一個字元數組的後面是有足夠空間的,它會直接把第二個字元數組中的字元挨個複製到第一個字元數組的後面。
那麼問題就來了,如果這兩個字元數組的記憶體空間是緊挨著的,那麼當執行strcat時,第二個字元數組的就會被覆蓋掉。這就是緩衝區溢位。
所以在使用strcat拼接兩個字串前,一定要先判斷第一個字串後面是否有足夠的記憶體空間;如果不夠了,那就得手動擴容。那麼這一系列判斷+擴容操作都是需要程式員自己去完成的,有些麻煩。
3.2.2 Redis如何避免緩衝區溢位?
而SDS提供的所有修改字串的API中,都會判斷修改之後是否會記憶體溢出,如果會記憶體溢出,它會幫你進行記憶體擴容。
所以對於SDS而言,這一系列操作都由它來幫你完成,無需程式員手動判斷。
3.3 減少修改字串時記憶體重分配的次數3.3.1 什麼是『記憶體重分配』?
- 當我們使用append擴充字串時,我們首先要擴充當前字元數組的記憶體,然後再將第二個字元數組中的值一一複製進來,否則就有可能出現『緩衝區溢位』。這個過程就是『記憶體重分配』。
- 當我們需要截取字串後,我們需要釋放已經不被使用的記憶體空間,否則就可能出現『記憶體泄露』。這個過程也是『記憶體重分配』。
記憶體重分配過程會涉及複雜的演算法和系統調用,較為耗時。如果像C字串那樣,每次修改字串都要進行一次記憶體重分配,那麼效率是極底的,所以SDS使用了『空間預分配』和『惰性空間釋放』降低了重分配的頻率,從而提升效率。
3.3.2 SDS如何減少記憶體重分配次數?3.4 二進位安全 binary-safe3.4.1 什麼是『二進位安全』?
所謂『二進位安全』就是:往SDS裡面放什麼資料,取出來還是什麼資料。SDS不會對儲存的這些資料做任何修改、限制、過濾等。
3.4.2 SDS如何保證二進位安全?
C字串對存入的字串是有嚴格要求的:
1. 必須符合某種編碼(如ASKII)
2. 不能含有空格
而SDS對於儲存的資料沒有任何限制,因此稱為『二進位安全』。
3.5 相容C字串
C字串要求字元數組的末尾必須是\0,作為字串尾的標記。而SDS中的字元數組也遵循了這一規範,所以仍然可以使用C字串相關函數,因此避免了重複代碼。
-
頂
-
1
-
踩
-
0
查看評論