1. 程式人生 > >第一部分之壓縮列表(第七章)

第一部分之壓縮列表(第七章)

圖片 結構 length 無符號整數 合並 總結 而是 多少 整數

壓縮列表是列表鍵和哈希鍵的底層實現之一。壓縮列表是為了節約內存而開發的,是由一系列特殊編碼的連續內存塊組成的順序型數據結構。

【壓縮列表是一種數據結構,這種數據結構的功能是將一系列數據與其編碼信息存儲在一塊連續的內存區域,這塊內存物理上是連續的,邏輯上被分為多個組成部分,其目的是在一定可控的時間復雜讀條件下盡可能的減少不必要的內存開銷,從而達到節省內存的效果 ————大佬總結】

一.什麽時候使用壓縮列表?

兩種情況:

當一個列表鍵只包含少量列表項,並且每個列表項要麽是小整數值,要麽就是長度比較短的字符串。

當一個哈希鍵只包含少量鍵值對,並且每個減值對的鍵和值要麽是小整數值,要麽就是長度表較短

二. 壓縮列表的構成

一個壓縮列表可以包含任意多個節點(entry),每個節點可以保存一個字節數組或一個整數值。其就是一個字節數組(char *)。如圖:

技術分享圖片

除了entryx外,一個壓縮列表其它4部分是固定的。

Zlbytes:存儲一個無符號整數,固定4個字節長度,用來存儲壓縮列表所占用的內存字節數。當對壓縮列表進行內存重新分配時,不需要遍歷整個列表來計算內存大小。

Zltail:存儲一個無符號整數,固定4個字節長度,記錄壓縮列表尾節點距離起始地址有多少字節(偏移量),通過這個值,程序不需要遍歷整個列表就可以確定表尾節點的地址。

Zllen:壓縮列表包含的節點個數,固定兩個字節長度,最大只能表示65535個節點,當節點數目超過65535個時,該值無效。需要遍歷列表來計算節點的個數。

EntryX:列表節點,長度不定(長度由節點保存的內容決定),由列表節點緊挨著組成。

Zlend:壓縮列表結尾標誌,固定一個字節長度,固定值0xFF(十進制255)。

內存布局【壓縮列表就是一塊連續的內存區域】:

技術分享圖片

三,壓縮列表的節點

每個壓縮列表節點可以保存一個字節數組或一個整數值。結構如下圖:

技術分享圖片

1. previous_entry_length

  單位為字節,記錄壓縮列表中前一個節點的長度。那麽程序可以通過指正運算,根據當前節點的起始地址來計算出前一個節點的起始地址。壓縮列表的從表尾向表頭遍歷的操作就是使用這個原理。

  如果前一個節點的長度小於254個字節,那麽previous_entry_length長度為1個字節,前一個節點的長度就保存在這一個字節裏

  如果前一個節點的長度大於等於254個字節,那麽previous_entry_length長度為5個字節,第一個字節設置為x0FE(十進制254),之後的四個字節保存前一個節點的長度

2. encoding

保存了節點的content的內容類型和長度,encoding類型一共有兩種,一種是字節數組,一種是整數。

  A,字節數組:

    當保存字節數組時,編碼長度有三種情況:
      1字節:值的最高位00,content保存的值長度小於等於63字節

      2字節:值的最高位01,content保存的值長度小於等於16383字節

      5字節:值的最高位10,content保存的值長度小於等於4294967295字節

技術分享圖片

  B,整數:

    保存整數時,長度位一個字節,值的最高位用11開頭

技術分享圖片

3. content

保存節點的值,節點的值可以是一個字節數組或整數,值的類型和長度由節點的encoding屬性決定。

4. 總結:

我們發現encoding第一個字節的前2比特可以區分是字節數組(以及字節數組類型)還是整數;

是整數時,第3、4比特可以區分整數的類型;當content的前4個比特都是1時,後4個比特才能區分整數類型;

四,壓縮列表的原理:

相信到這裏,我們都明白了壓縮列表的原理壓縮列表並不是對數據利用某種算法進行壓縮,而是將數據按照一定規則編碼在一塊連續的內存區域,目的是節省內存。

五,壓縮列表的應用:

Redis中,不同的數據類型廣泛地應用了壓縮列表編碼,整理如下表:

技術分享圖片

1. 問題思考

Redis為什麽使用壓縮列表?

使用壓縮列表的好處是什麽?

壓縮列表的應用對與我們使用內存有沒有什麽啟發?

2. 大佬的總結

Redis對於每種數據結構、無論是列表、哈希表還是有序集合,在決定是否應用壓縮列表作為當前數據結構類型的底層編碼的時候都會依賴一個開關和一個閾值,開關用來決定我們是否要啟用壓縮列表編碼,閾值總的來說通常指當前結構存儲的key數量有沒有達到一個數值(條件),或者是value值長度有沒有達到一定的長度(條件)。任何策略都有其應用場景,不同場景應用不同策略。為什麽當前結構存儲的數據條目達到一定數值使用壓縮列表就不好?壓縮列表的新增、刪除的操作平均時間復雜度為O(N),隨著N的增大,時間必然會增加,他不像哈希表可以以O(1)的時間復雜度找到存取位置,然而在一定N內的時間復雜度我們可以容忍然而壓縮列表利用巧妙的編碼技術除了存儲內容盡可能的減少不必要的內存開銷,將數據存儲於連續的內存區域,這對於Redis本身來說是有意義的,因為Redis是一款內存數據庫軟件,想辦法盡可能減少內存的開銷是Redis設計者一定要考慮的事情。

另外,經過仔細琢磨,我認為使用壓縮列表的好處除了節約內存之外,還有減少內存碎片的作用,我把這種行為叫做"合並存儲",也就是將很多小的數據塊存儲在一個比較大的內存區域,試想想,如果我們將要存儲的數據都是很小的條目,我們為每一個數據條目都單獨的申請內存,結果是這些條目將有可能分散在內存的每一個角落,最終導致碎片增加,這是一件令人頭疼的事情。

六,參考資料:

書籍:《redis設計與實現》

博客:https://my.oschina.net/andylucc/blog/715325,https://segmentfault.com/a/1190000015296224,https://blog.csdn.net/u012658346/article/details/51321337

第一部分之壓縮列表(第七章)