redis經過前面幾篇的數據結構構鍵了一個對象系統,這個對象系統包含了字符串對象,列表對象,哈希對象,集合對象,有序集合對象redis
每個對象都是一個redisobjectwindows
typedef struct redisObject { // 類型 unsigned type:4; // 編碼 unsigned encoding:4; // 指向底層實現數據結構的指針 void *ptr; // ... } robj;
type表示類型,有5種,就是緩存
REDIS_STRING,REDIS_LIST,REDIS_HASH,REDIS_SET,REDIS_ZSET服務器
編碼表示的就是底層的實現,由於每一種對象都至少有兩種以上的實現方式。ptr指向的就是底層實現的數據結構數據結構
字符串對象的編碼能夠是int,raw,embstrapp
int針對的是整數函數
若是字符串的長度小於39,那麼使用embram,不然使用raw優化
embstr和raw的區別編碼
(1)embstr是連續的,object和sds是一塊連續的內存,這樣的話分配內存和釋放內存都不是兩次,而是一次spa
(2)充分利用緩存的優點
double類型其實也是字符串類型的
當時用的時候會從字符串類型轉換爲double類型
int和embstr在知足條件的時候都會轉換爲raw編碼,好比一個整數10085 appending一個字符串的話就不在是一個整數了
另外embsr不能夠修改的,他是隻讀的,若是要修改的話,他會自動轉換爲raw以後再進行修改
列表對象:
列表對象的編碼可使壓縮列表和雙端鏈表,若是其中有字符串的話,字符串是字符串對象的表示,說明字符串對象能夠被其餘的對象嵌套
編碼轉換
(1)每個元素得長度都小於64,
(2)數量小於512,
知足上面兩個條件的話就是用壓縮列表,不然的話使用雙端鏈表
哈希對象
哈希對象的編碼能夠是壓縮列表和字典
以下圖所示
至於編碼的轉換,和上面的是同樣的,若是兩個都知足,就使用壓縮列表,不然使用字典
ps:注意這兩個限制條件在redis.conf的配置文件中是能夠修改的
集合對象:
集合對象的編碼能夠是整數集合和hashtable
看下面:
編碼的轉換條件
(1)都是整數
(2)元素數量不超過512個
知足以上條件使用整數集合,不然的話使用hashtable
有序集合對象:
編碼能夠是壓縮列表和跳躍表
壓縮列表實現的話,使按照分值排序,而且存儲的話對象在前,分值在後
zset中基於跳躍表實現的話,就是講分值從小到大排序,創建一個跳躍表,可是額外還須要一個字典,記錄對象和分值的映射,這樣的話對於ZSCORE命令,咱們能夠在O(1)的時間複雜度就能夠得到到指定對象的分值
二者結合,不管是有序遍歷仍是得到指定元素,都會擇優選擇,下降時間複雜度
編碼轉換
(1)長度都小於64
(2)數量不超過128個
這兩個都知足就是用壓縮列表,否者就是用skiplist做爲編碼
額外對於對象還有不少優化和處理
(1)多態:不少命令都是具備多態的性質,就是能夠處理多種命令
在執行一個命令的時候,咱們首先會根據值對象的類型去判斷這個命令可否執行,若是能夠的話,咱們還會根據值對象的編碼方式選擇正確的API去執行
好比上面,咱們就能夠認爲LLEN是多態的,多態能夠包括基於類型的多態,和基於編碼的多態
(2)內存管理:
對於redisobject咱們基於引用計數原值,定義在redisobject結構裏面的refcount int,當對象引用計數下降爲0的時候,釋放對象。這個有點相似windows線程回收機制,採用計數原值,關閉handle減一,線程函數退出減一,爲0的時候自動回收線程資源
(3)對象共享:
redis中多個鍵的值同樣的話,會使值指針只想一塊內存,引用計數增長,redis服務器初始化的時候會默認建立0-9999字符串,因此他們的引用計數在還沒使用的時候就是1了
(4)空轉時長:
redisobject中有個lru,表示最後訪問的時候
經過idletime能夠求出多久沒有被訪問了,就是當前時間和lru時間差(空轉時長)
可是ps(這個命令不會修改lru屬性)
若是服務器設置了maxmemory選項,那麼當內存達到上線了,服務器會優先空轉時間長的進行釋放