Redis源碼解析4 – 數據類型之 String List STRING string類型的數據在redis中有兩種編碼方式: 1.RAW 這表示一個原始字符串對象,robj中的ptr指針指向一個sds類型的內存塊 sds是一個帶長度信息的內存塊,用于存儲 二進制安全 的字符串 2. INT 這表示一個編碼
Redis源碼解析4 – 數據類型之 String & List
STRING
string類型的數據在redis中有兩種編碼方式:
1.?RAW
? ? 這表示一個原始字符串對象,robj中的ptr指針指向一個sds類型的內存塊
? ? sds是一個帶長度信息的內存塊,用于存儲二進制安全的字符串
2. INT
? ? 這表示一個編碼為整數的字符串對象,robj中的ptr指針被強行轉化為一個long型變量以存儲整數
? ? 數字類型的字符串,比如“123456”,都會被編碼為整型
? ? 這樣做的目的就一點,節省內存。就以字符串“123456”為例,
? ? (1) 存為RAW類型,共消耗內存為:sizeof(robj) + sizeof(sdshdr) + strlen(“123456”)
? ? ? ? ?32位系統為26字節,64位系統下為30字節
? ? (2) 存為INT類型,共消耗內存為:sizeof(robj)
? ? ? ? ?32位系統為12字節,64位系統下為16字節
? ? 可以看出,節省的內存還是挺多的
? ? 如果字符串更長一些,比如“123456789”,節省的內存就可觀了
? ? 一點小提示,在Redis中,64位的bigint,香港虛擬主機,是按RAW格式存儲的
? ??之所以這么做,完全是為了兼容不同的系統
? ? 在實際使用中,如果你確定你的機器都是64位的(MS現在很少32位機了),可以改改源代碼,多節省一些內存?
?
再加一幅圖,更直觀的說明一下
? ?
OK,在Redis中,String是最基本的類型,也很簡單,從上圖可以較清晰的看出String的組織方式了
題外話,不知道有同學注意到沒有,robj中的ptr居然是指向sdshdr內存塊的中間部分,而不是指向內存頭
從這一點看,Redis的代碼也挺“野”的
?
LIST
list數據有兩種編碼方式:
?
1. linked_list
? ? 這就是一個傳統的雙向鏈表,帶頭尾指針,其頭尾操作都只有O(1)的復雜度
? ??
?
2. ziplist
? ? 這是一種壓縮編碼的鏈表,它將所有的鏈表數據全部整合進一整塊內存中,相比傳統的鏈表,節省很多內存
?
簡要說明一下上圖:
(1) ziplist使用一整塊連續的內存,這塊內存由三部分組成:
? ? ?(a) head塊,鏈表的頭信息,包括有 totalsize(鏈表總長度)、tailoffset(尾部最后一個元素的偏移字節數)、entrycount(entry個數)
? ? ?(b) entry塊,由一系列的 entry node 組成。node之間緊湊排列
? ? ? ? ? 每個node有 prevsize字段,表示前一個node的長度,用以反方向索引
? ? ? ? ? 有selfsize字段,表示當前node的長度
? ? ? ? ? 以及data字段,存放當前node的實際數據
? ? ? ? ? 這些字段都按一種特殊的形式編碼,具體參考上圖,已經比較清晰了
? ? ?(c) tail塊,虛擬主機,鏈表的尾部。只有一個字節,是一個填充碼。
(2) 向ziplist中增刪元素時,有較頻繁的內存重分配操作,香港服務器,以及較復雜的數值運算
? ? ?所以,當鏈表長度增加時,整個數據結構就會不堪重負
(3) redis用兩個閥值來控制 ziplist 與 linked_list 之間的轉換
? ? ?(a)?list_max_ziplist_entries:當鏈表元素的個數超過該值,自動轉化為 linked_list,該值默認512
? ? ?(b)?list_max_ziplist_value:當鏈表中某個字符串元素的長度超過該值,自動轉化為 linked_list,該值默認64
? ? ?(c) 以上兩值均可通過配置文件修改
posted on