redis 內(nèi)部數(shù)據(jù)結(jié)構(gòu)(1.1)-字符串

簡單動態(tài)字符串 sds

數(shù)據(jù)結(jié)構(gòu)

typedef char *sds;

struct sdshdr {
        // 記錄 buf 數(shù)組中已使用字節(jié)的數(shù)量
        // 等于 SDS 所保存字符串的長度
        int len;
        // 記錄 buf 數(shù)組中未使用字節(jié)的數(shù)量
        int free;
        // 字節(jié)數(shù)組,用于保存字符串
        char buf[];
};

與 C 中字符串結(jié)構(gòu)不同的是,C語言需要遍歷字符串以確認字符串結(jié)束的位置(On),SDS 的效率是 O1.

SDS 的好處不止于此,還可以避免在修改 buf,尤其是追加情況下, 的內(nèi)存溢出問題。

內(nèi)存分配

直接引用別人博客里說的內(nèi)容吧。

1. 在函數(shù)sdsnewlen中,根據(jù)是否需要初始化使用zmalloc和zcalloc兩個不同函數(shù)。
2. 計算字符串長度的時候,直接使用函數(shù)sdslen,不需要調(diào)用strlen。
3. 需要擴展free的空間時, 需要調(diào)用函數(shù)sdsMakeRoomFor, 該函數(shù)空間分配策略比較有意思, 如果free>=addlen,直接返回。 否則判斷free+addlen是否小于SDS_MAX_PREALLOC這個宏, 如果小于,那么這次就分配2*(free+addlen)的空間, 這樣每次多分配一陪的空間; 否則就分配free+addlen+SDS_MAX_PREALLOC的空間。 這樣可以控制最大多分配多少的空間, 以至于不要浪費太多空間。例如: sds old=sdsnew("test one"); sds new=sdscat(old,"test"); 此時有12的空余空間, 如果再次調(diào)用``sdscat(new,”test”)``, 那么就不需要分配空間。
4. 在函數(shù)sdscatvprintf中, 空間申請是以16,32,64..這樣增長的, 無處不透露提高性能。
5. 在函數(shù)sdscmp中, 調(diào)用memcmp, 性能要比strcmp好, 而且還是二進制安全的。
6. 在函數(shù)sdssplitlen中, 默認分配的數(shù)組為5, 然后按照2的倍數(shù)進行增長, 這樣做法,有點浪費空間,但是加快速度,不要每分割出來一個字符串就要申請空間。 比較的時候把seplen為1分出來, 也是加快字符串比較速度的考慮, 大部分時候應(yīng)該是seplen為1。

增加的情況

為什么需要用 free,為什么需要預(yù)先分配內(nèi)存空間?
其實目的很明確,就是避免過多次的分配內(nèi)存空間,因為這個過程時間消耗很大。如果需要修改字符串,檢查 free 是否夠用,如果夠則不分配內(nèi)存,否則分配。達到減少內(nèi)存變動次數(shù)的目的。

預(yù)分配空間的大小是這樣決定的:

1 length >> 20 > 1,length 對于的大小超過 1M,分配 1M 的free
2 length >> 20 <=1, 分配與 length 相同大小的 free

減少的情況-惰性空間釋放

用幾個圖來說明釋放時候 free 的變化情況:

初始狀態(tài)
釋放全部 x,y 的狀態(tài)圖
釋放后追加的狀態(tài)

其他

SDS 是二進制安全的,比 C 只能保存文本數(shù)據(jù)相比具有更多的優(yōu)勢??梢约嫒莶糠?C 語言中的字符串函數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容