SDS結構(簡單動態字符串)
結構如下
struct stdhdr { int len //記錄buff數組中已使用字節的數量 int free //記錄buff數組中未使用字節的數量 char buff[] //字節數組,用於保存字符串 }
(1)free 屬性為0,表示這個SDS沒有分配任何未使用空間。
(2)len 屬性為5,表示這個SDS保存着一個5字節長的字符串
(3)buf 屬性是一個char類型的數組,數組的前五個字節分別保存了,'R' 'e' 'd' 'i' 's' ,而最后一個字節保存了空字符 '\0' (以空字符結尾),最后一個空字節不計算在len屬性里面。
SDS字符串和C字符串的區別
1.通過使用SDS字符串(len記錄字符串長度),使得獲取字符串長度的復雜度從O(N)變為O(1)
2.杜絕緩存區溢出,C字符串不記錄自身長度,在拼接字符串時可能造成緩存區溢出
3.通過未使用空間free,減少修改字符串帶來的內存重分配次數
空間預分配
空間預分配用於優化 SDS 的字符串增長操作: 當 SDS 的 API 對一個 SDS 進行修改, 並且需要對 SDS 進行空間擴展的時候, 程序不僅會為 SDS 分配修改所必須要的空間, 還會為 SDS 分配額外的未使用空間。
其中, 額外分配的未使用空間數量由以下公式決定:
- 如果對 SDS 進行修改之后, SDS 的長度(也即是 len 屬性的值)將小於 1 MB , 那么程序分配和 len 屬性同樣大小的未使用空間, 這時 SDS len 屬性的值將和 free 屬性的值相同。 舉個例子, 如果進行修改之后, SDS 的 len 將變成 13 字節, 那么程序也會分配13 字節的未使用空間, SDS 的 buf 數組的實際長度將變成 13 + 13 + 1 = 27 字節(額外的一字節用於保存空字符)。
- 如果對 SDS 進行修改之后, SDS 的長度將大於等於 1 MB , 那么程序會分配 1 MB 的未使用空間。 舉個例子, 如果進行修改之后, SDS 的 len 將變成 30 MB , 那么程序會分配 1 MB 的未使用空間, SDS 的 buf 數組的實際長度將為 30 MB + 1 MB + 1 byte 。
通過空間預分配策略, Redis可以減少連續執行字符串增長操作所需的內存重分配次數。
惰性空間
釋放惰性空間釋放用於優化SDS的字符串縮短操作:當 SDS的API需要縮短 SDS保存的字符串時, 程序並不立即使用內存重分配來回收縮短后多出來的字節, 而是使用 free 屬性將這些字節的數量記錄起來, 並等待將來使用。