1. 程式人生 > 其它 >Redis-如何減少修改字串帶來的記憶體分配過程消耗-深入理解

Redis-如何減少修改字串帶來的記憶體分配過程消耗-深入理解

技術標籤:Redisredis簡單動態字串

1、Redis字串的特點

  • 已知Redis的鍵值對的字串物件,值也可以是字串物件,值還可以是列表物件、雜湊物件、集合物件、有序集合物件總共這五種物件。
  • Redis的底層實現語言是經典的C語言,Redis的字串定義與C語言的字串定義有一些區別
    – 1、C語言的字串物件是以空字元結尾的字元型別陣列,有多少個字元該陣列就是多大的
    – 2、Redis使用的是簡單動態字串(SDS, simple dynamic string)的抽象型別,SDS除了用來儲存Redis的字串物件之外,還可以用作緩衝區。

SDS的資料結構定義如下:

strcut sdshdr{
int len;//用來儲存陣列中已使用位元組的數量=SDS所儲存的字串的長度 int free;//用來儲存陣列中未使用位元組的數量 int buf[];//位元組陣列,用來儲存字串。大小=len + free }

SDS的結構用影象表示如下,以儲存字串"Redis"的一個SDS為例:
SDS示例

  • 從中可以看出,free=0,表示該SDS的未使用空間大小為0;
  • len=5,表示SDS的儲存的字串的大小為5位元組;
  • buf的屬性是一個char型別的陣列,其中儲存瞭如上所示的字元,0個未使用字元空間,還要’結尾處的/0‘空字元。
  • 如果要獲取該SDS儲存的字串的長度,不用遍歷字串,直接使用len的值就行。獲取長度方便,就能有效防止緩衝區溢位的風險,還能減少修改字串(如拼接等操作)帶來的記憶體重分配資源消耗

2、SDS如何實現減少修改字串帶來的記憶體重分配

結論:SDS使用空間預分配和惰性空間釋放兩種機制來避免標題所示問題

記憶體重分配:字串拼接可能帶來緩衝區溢位,字串縮短可以造成記憶體洩露,這就需要對記憶體空間進行重分配,這種操作涉及到的演算法複雜,可以需要執行系統級別的呼叫,所需要的資源和時間比較多,要儘量避免,可以使用空間換時間的策略。

(1)空間預分配

當對SDS的API對SDS進行修改,需要對SDS進行空間擴充套件的時候,會帶來兩個空間的擴充套件:所必須的字串空間,額外的未使用空間

  • len的長度<1MB時,分配的未使用空間大小=len
  • len的長度>=1MB時,分配的未使用空間大小=1MB
  • 也就是len<1MB的時候free=len,大於的時候free=1MB
    通過空間預分配策略,Redis可以減少連續執行字串增長操作所需要的記憶體重分配次數。
//示例:
sdscat(s,"Tutorial");//將s和"Tutorial"字串拼接

對標題1的SDS執行以上程式時,因為未使用字串空間不夠,將執行一次記憶體重分配操作:len修改為拼接之後的大小並填入資料,free變為13位元組。
在這裡插入圖片描述
如果再次執行上述拼接程式碼,free空間夠用,將不會產生記憶體重分配。

(2)惰性空間釋放

惰性空間釋放針對優化SDS的字串縮短操作,當SDS的API需要縮短SDS所儲存的字串的時候,並不一定要立刻進行記憶體重分配來釋放空閒出來的位元組

  • 將釋放出來的位元組轉換為空閒位元組,同時更新free屬性的大小
  • 此操作能避免縮短字元帶來的記憶體重分配操作,還為可能的增長操作帶來了快取的空間

參考資料:<Redis設計與實現>第一章