Redis數據結構—簡單動態字符串(SDS)


Redis—簡單動態字符串(SDS)

這兩天我原本打算學習一下若依這個老生常談的開源的后端管理系統(如果你沒聽過,在將來的某一天也會聽說甚至用到),拿到這個系統的前后端分離版后,若依碼雲項目地址,一啟動發現需要Redis服務,遂轉戰學習Redis(Redis也是老生常談了~)

白澤預計將花費一個月的時間去學習Redis的設計與實現,並盡量保證文章的輸出,我們共勉~

本次介紹一個Redis的數據類型,簡單動態字符串,SDS(simple dynamic string),因為Redis是用C語言寫的,而且C語言本身就有字符串這個數據類型,那就要提出疑問:為啥不直接用C語言的字符串,而要新發明一種新的字符串類型呢?

事實上,即使我沒學過Redis,也聽聞過它可以以鍵值對的形式存儲數據,它很快。但它的快絕不僅僅是鍵值對的存儲形式帶來的,SDS的存在就是幫助Redis更快,更安全~

SDS的定義

//sds的存儲結構
struct sdshdr {
	int len;	//記錄buf數組中已經使用的字節的數量
	int free;	//記錄buf數組中還未使用的字節的數量
	char buf[]; //字節數組,用於保存字符串
};

很明顯,SDS內部就是一個C語言的字符串(字節數組),只是多了兩個變量存放當前的長度和剩余的長度,下面這張圖模擬了當sds存放了 'Redis' 字符串后的情況

SDS遵循C字符串以空字符結尾的慣例,保存空字符的1字節空間不計算在SDS的len屬性中,好處是SDS可以直接重用一部分的C字符串函數庫中的函數(只要SDS內部的buf也是以'\0'結尾,那就是一個C語言的字符串啊,有啥不能用的~)

當然還可以像下面這張圖這樣,5為已使用的buf數組的長度,5為未使用的數組的長度,而下面這種場景才是更多的出現在Redis中的。接下來就講講通過free,len和C語言字符串buf的配合,如何使Redis比單純使用C語言的字符串更快,更安全吧

SDS與C字符串的區別

1. 常數復雜度獲取字符串長度:

因為SDS的free直接就記錄了buf數組的使用長度,因此如果要獲取buf的長度,SDS只需要O(1)的時間復雜度,而C的字符串需要O(N),因此更快!

2. 杜絕緩沖區溢出:

如上圖:因為C語言字符串不記錄本身的長度,如果原本連續的內存中存放了str1 = 'Redis',str2 = 'MySQL'兩個字符串,此時執行某個操作將str1替換為下方的str1 = 'Hello BaiZe',那么str1的內容將會溢出到原本str2的空間中

如果使用SDS的API修改SDS內容時,如果buf剩余空間不足,API將先擴容SDS的空間,然后再修改buf數組的內容。因此更安全!

3. 減少修改字符串時帶來的內存重分配次數

C語言的字符串無論是增長還是縮短,每次都需要程序重新分配內存(因為可能會影響到內存已經存在的數據),這就意味着每次都將消耗一定資源去完成這個任務。

而Redis作為數據庫,數據可能會頻繁修改,每次都去內存重分配就慢了。而在SDS中,len、free和buf數組相配合,就能從兩個角度去優化頻繁修改時時間的消耗

  • 空間預分配:

    當SDS需要擴容的時候(進行一次內存重新分配),擴容后len小於1MB,那么程序分配和len屬性相同大小的free空間,則本次擴容后SDS的free會等於此時SDS的len,當然空字符'\0'依舊會占額外的一字節的空間,本次擴容結束后SDS所占空間為:len + free + 1byte

    如果擴容后len大於1MB,那么程序會分配1MB的未使用free空間(所以最多就是給你分配1MB的free),此時SDS所占用空間為:len + free(1MB) + 1byte

    說到底空間預分配的目的就是每次擴容時多申請一些空間(每次擴容也是一次內存的重新分配),以備下次buf數組長度增長時或許可以不去申請內存的重新分配,但最差的情況下每次多申請的空間都不夠下次用的,那依舊退化為C語言字符串擴容時每次都需要重新分配內存的情況

  • 惰性空間釋放

    有擴容就有縮短,當SDS的buf變短時,程序並不直接進行內存的重新分配,而是只是增加free的值,這比進行一次內存重新分配縮短buf快很多!buf數組多余的5個空間依舊保留,如果將來要對SDS進行增長操作還能用上。當然如果有需要SDS也提供了API對這些空間進行真正的釋放

4. 二進制安全

C語言字符串以空字符'\0'判斷字符串是否結束,那么下面這種含有兩個空字符的字符串就無法完整地存入C語言的字符串,因此也無法存儲二進制數據(圖片、視頻、音頻等),但是SDS的長度是由len定義的,因此內部也可以存放空字符'\0',也可以用於保存二進制數據(啥都能存

小結

C字符串和SDS的區別


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM