redis沒有直接使用c語言傳統的字串表示,而是自己構建了一種名為簡單動態字串(sds)的抽象型別,並將其作為redis的預設字串表示,即redis中包含字串值的鍵值對在底層都是由sds實現的。
每個sds.h/sdshdr結構表示乙個sds的值,如下所示:
sds遵循c字串以空字元結尾的管理,儲存空字元的1位元組空間不計算在sds的len屬性裡面。為空字元分配1位元組空間並新增到字串末尾是由sds函式自動完成,所以此空字元對於sds使用者來說是透明的。遵循空字元結尾的好處是可以直接重用一部分c字串函式庫裡面的函式。下面這個sds示例中,為buf陣列分配了五位元組未使用空間,所以free屬性為5。
2.1 常數複雜度獲取字串長度
要獲取乙個c字串的長度,需要遍歷整個字串,但是sds在len屬性中記錄了sds本身的長度,所以獲取乙個sds長度的複雜度僅為o(1)。
2.2 杜絕緩衝區溢位
c字串不記錄自身長度會容易造成緩衝區溢位。但sds的空間分配策略杜絕了發生緩衝區溢位的可能性:當sds api需要對sds進行修改時,api會先檢查sds的空間是否滿足修改所需的要求,如果不滿足的話,api會自動將sds的空間擴充套件至執行修改所需的大小,然後才執行實際的修改操作,所以使用sds不需手動修改sds的空間大小,也不會有緩衝區溢位問題。
2.3 減少修改字串時帶來的記憶體重分配次數
c字串不記錄自身長度,對於有n個字元的c字串來說,底層實現總是乙個n+1個字元長的陣列(額外的儲存空字元)。由於這種關係,所以每次增長或者縮短乙個c字串,程式總要對儲存這個c字串的陣列進行一次記憶體重分配操作:
因為記憶體重分配涉及複雜的演算法,且可能需要執行系統呼叫,所以通常比較耗時。為避免這種缺陷,sds通過未使用空間解除了字串長度和底層陣列長度之間的關聯:在sds中,buf陣列的長度不一定就是字元數量加一,陣列裡面可以包含未使用的位元組,而這些位元組的數量就由sds的free屬性記錄。
通過未使用空間,sds實現了空間預分配和惰性空間釋放兩種優化策略。
空間預分配
空間預分配用於優化sds的字串增長操作:當要擴充套件sds空間時,程式不僅會為sds分配修改所必須要的空間,還會為sds分配額外的未使用空間。額外分配的未使用空間數量由以下公式決定:
通過空間預分配策略,redis可減少連續執行字串增長操作所需的記憶體分配次數。當然在擴充套件sds空間之前,sds api會先檢查未使用空間是否則溝,足夠的話會直接使用未使用空間,而無需執行記憶體重分配。
惰性空間釋放
惰性空間釋放用於優化sds的字串縮短操作:當要縮短sds儲存的字串時,程式並不立即使用記憶體重分配**縮短後多出來的位元組,而是使用free屬性將這些位元組的數量記錄起來,並等待將來使用。
當然sds也提供了相應的api,讓我們可以再有需要時,真正地釋放ds的未使用空間,所以不用擔心惰性空間釋放策略會造成記憶體浪費。
2.4 二進位制安全
c字串中的字元必須符合某種編碼(比如ascii),並且除了字串的末尾之外,字串裡面不能包含空字元,否則最先被程式讀入的空字元將被誤認為是字串結尾。但sds的api都是二進位制安全的,所有sds api都會以處理二進位制的方式來處理sds存放在buf陣列裡的資料,程式不會對其中的資料做任何限制、過濾或者假設,資料在寫入時是什麼樣的,它被讀取時就什麼樣。
這也就是我們將sds的buf屬性稱為位元組陣列的原因—redis不是用這個陣列來儲存字元,而是用它儲存一系列二進位制資料。
2.5 相容部分c字串函式
雖然sds的api是二進位制安全的,但它們一樣遵循c字串以空字元結尾的慣例:這些api總會將sds儲存的資料的末尾設定為空字元,並且總會在為buf陣列分配空間時多分配乙個位元組來容納這個空字元,這是為了讓那些儲存文字資料的sds可以重用一部分庫定義的函式。
2.6 總結
c字串sds獲取字串長度的複雜度為o(n)
獲取字串長度的複雜度為o(1)
api是不安全的,可能會造成緩衝區溢位
api是安全的,不會造成緩衝區溢位
修改字串長度n次必然需要執行n次記憶體重分配
修改字串長度n次最多需要執行n次記憶體重分配
只能儲存文字資料
可以儲存文字或二進位制資料
可以使用所有庫中的函式
可以使用一部分庫中的函式
Redis 簡單動態字串
在c語言中,乙個結構體中最後乙個成員的位址減去第乙個成員的位址,就是該結構體的大小 例如 struct sdshdr buf的位址減去len的位址,正好等於sizeof sdshdr 在c 中 char str nihao 是不被允許的,但是c語言中可以,並且可以直接列印str 輸出nihao,和c...
redis簡單動態字串
redis內部使用sds,簡單動態字串,sds是什麼 dynamic t包含字串長度,空間使用率,已使用,未使用等資訊的乙個結構體 sds比c語言字串的優點 獲取字串長度不需要進行遍歷,時間複雜度為o 1 杜絕緩衝區溢位 對sds進行修改的時候,api會先檢查sds的空間是否足夠,如果不需要的話,a...
Redis之簡單動態字串
sds的介紹 redis中字串並沒有使用c語言傳統的字串,而是構建了一種名為簡單動態字串 sds sds是redis的預設字串標識。redis裡面的c語言字串用在一些無需對字串值進行修改的地方,例如列印日誌redislog redis warning,redis is now ready to ex...