1. 程式人生 > >Redis知識總結--string的內部實現

Redis知識總結--string的內部實現

SDS(Simple Dynamic String)

String的資料結構是一個位元組陣列,但簡單的獲取陣列長度的時間複雜度就是O(n),這對於單執行緒的redis來講是不能接受的,因此string在redis中的實現是SDS類,SDS類的結構總體如下(C已忘,只能用java大致表達下):

public class SDS {
  // string內容的真實長度,為了節約記憶體,這裡是個泛型
  // 當內容較少時,使用byte或short
  private T length;
  // 為string分配的記憶體空間大小,同樣為了節約記憶體,用了泛型
  private T capacity;
  // string的真實內容,使用位元組陣列儲存
  private byte[] content;
  // 特殊標記,不知道幹嘛的
  private byte flags;
}

如上,長度直接儲存下來了--雖然兩者沒什麼關聯,但我想到了mysql的Myisam引擎,也是直接將表的資料條數直接儲存下來--這樣要獲取長度直接取值即可;

embded 和 RAW

使用debug object命令會發現,不同長度的string的encoding有embed和raw兩種型別,也是為了節省空間,64位元組及以下的string會使用embed儲存,以上使用RAW儲存(不同redis版本下可能會有不同的界限),之所以使用64為界是因為記憶體分配函式malloc等都是一次分配2的若干次冪大小的記憶體,另外即使分配64位元組給string使用,content也只有44位元組的記憶體可以儲存,原因正是因為下面的redis頭物件也佔了坑

RedisObject

public class RedisObject {
  // 資料型別,只使用4bit
  private int4 type;
  // 資料的encoding型別,只使用4bit
  private int4 encoding;
  // 資料的lru資訊,只使用24bit
  private int24 lru;
  // 該資料的引用計數,使用32bit
  private int32 refcount;
  // 這是個指標,指向資料物件,在64位作業系統下,使用8個位元組
  private Poniter *p;
}

可以發現,物件頭至少使用16個位元組,而假使SDS的三個輔助屬性都只使用1位元組的話,content也就只剩下64-19=45位元組的空間可以使用了,還有一個位元組用來儲存字串的結尾字元,這個字元通常使用的是null,而在redis中使用的是\0,\0使用了1個位元組,content的可用有效字元就僅剩44位元組了