咱們繼續接着上一篇博客,今天來看看內存映射數據結構。算法
上篇咱們講了內部數據結構,雖然內部數據結構很是強大,可是建立一系列完整的數據結構自己也是一件至關耗費時間的工做,當一個對象包含的元素數量並很少,或者元素自己的體積並不大時,使用代價高昂的內部數據結構並非最好的辦法。所以咱們會用內存映射數據結構來代替內部數據結構。數組
內存映射數據結構是一系列通過特殊編碼的字節序列,建立他們所消耗的內存一般比做用相似的內部數據結構要少得多,若是使用得當,內存映射數據結構能夠爲用戶節省大量的內存。不過,內存映射數據結構的編碼和操做方式要比內部數據結構複雜的多,因此內存映射數據結構所佔用的CPU時間會比做用相似的內部結構要多。數據結構
2.1整數集合函數
整數集合(intset)用於有序、無重複地保存多個整數值,他會根據元素的值,自動選擇該用什麼長度的整數類型來保存元素。ui
2.1.1 整數集合的應用編碼
intset是集合鍵的底層實現之一,若是一個集合知足:spa
* 值保存着整數元素;指針
* 元素的數量很少;code
那麼就會使用intset來保存集合元素。對象
2.1.2 數據結構和主要操做
typedef struct intset { // 保存元素所使用的類型的長度 uint32_t encoding; // 元素個數 uint32_t length; // 保存元素的數組 int8_t contents[]; } intset;
encoding 的值能夠是如下三個常量的其中一個(定義位於intset.c ):
#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))
contents數組是實際保存元素的地方,數組有一下兩個特性:
* 沒有重複元素;
* 從小到大排序;
contents的 int8_t類型只是做爲一個佔位符使用,intset不使用int8_t類型保存任何元素。新增元素默認的encoding是int16_t,當添加的新元素不適合於當前intset的編碼類型時,intset集合將會進行升級。
2.1.3 小結
* intset用於有序、無重複的保存多個整數值。他會根據元素的值,自動選擇該用什麼長度的整數類型來保存元素;
* 當一個位長度更長的整數值添加到intset時,須要對intset進行升級,新intset中的每一個元素的位長度都等於新添加值的位長度,但原有元素的值不變;
* 升級會引發整個intset進行內存重分配,並移動集合中的全部元素,這個操做的複雜度爲O(N);
* intset只支持升級,不支持降級;
* intset是有序的,程序使用二分法查找算法來實現查找操做,複雜度爲O(lgN);
2.2 壓縮列表
ziplist 是由一系列特殊編碼的內存塊構成的列表,一個ziplist 能夠包含多個節點(entry),每一個節點能夠保存一個長度受限的字符數組(不以\0結尾的char數組)或者整數,包括:
• 字符數組
– 長度小於等於63 (26 - 1)字節的字符數組
– 長度小於等於16383 (214 - 1)字節的字符數組
– 長度小於等於4294967295 (232 - 1)字節的字符數組
• 整數
– 4 位長,介於0 至12 之間的無符號整數
– 1 字節長,有符號整數
– 3 字節長,有符號整數
– int16_t 類型整數
– int32_t 類型整數
– int64_t 類型整數
由於ziplist節約內存的性質,它被哈希鍵、列表建和有序集合鍵做爲初始化的底層實現來使用。
2.2.1 ziplist的結構:
由於ziplist header 部分的長度老是固定的(4 字節+ 4 字節+ 2 字節),所以將指針移動到表頭節點的複雜度爲常數時間;除此以外,由於表尾節點的地址能夠經過zltail 計算得出,所以將指針移動到表尾節點的複雜度也爲常數時間。
由於ziplist 由連續的內存塊構成,在最壞狀況下,當ziplistPush 、ziplistDelete 這類對節點進行增長或刪除的函數以後,程序須要執行一種稱爲連鎖更新的動做來維持ziplist 結構自己的性質,因此這些函數的最壞複雜度都爲O(N2) 。不過,由於這種最壞狀況出現的機率並不高,因此大能夠放心使用ziplist ,而沒必要太擔憂出現最壞狀況。
2.2.2 節點的構成:
pre_entry_length:記錄了前一個節點的長度,經過這個值,能夠進行指針計算,從而跳轉到上一個節點。(注:若前一個節點的長度小於254字節,則使用一個字節保存pre_entry_length的值,若大於等於254,則使用5個字節保存,其中第一個字節保存254,後4個字節保存前一個節點的實際長度);
encoding:記錄了content的數據類型,長度爲2個bit,它的值能夠是00、0一、10和11(其中00、01和10表示Content中保存着字符數組;11表示content中保存着整數);
length:記錄了content的數據長度;
content:保存着節點的內容
2.2.3 小結:
* ziplist是由一系列特殊編碼的內存塊構成的列表,它能夠保存字符數組或整數值,它仍是哈希鍵、列表鍵和有序集合鍵的底層實現之一。
* 添加和刪除ziplist節點有可能會引發連鎖更新,所以,添加和刪除操做的最壞複雜度爲O(N2),不過,由於連鎖更新的出現機率並不高,因此通常能夠將添加和刪除操做的複雜度視爲O(N)。