欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > redis內部數據結構之SDS簡單動態字符串詳解

redis內部數據結構之SDS簡單動態字符串詳解

熱門標簽:最簡單的百度地圖標注 太原營銷外呼系統 地圖標注如何即時生效 地圖標注費用 竹間科技AI電銷機器人 百度商家地圖標注怎么做 玄武湖地圖標注 西藏教育智能外呼系統價格 小紅書怎么地圖標注店

前言

reids 沒有直接使用C語言傳統的字符串表示(以空字符結尾的字符數組)而是構建了一種名為簡單動態字符串的抽象類型,并為redis的默認字符串表示,因為C字符串不能滿足redis對字符串的安全性、效率以及功能方面的需求

1、SDS 定義

在C語言中,字符串是以'\0'字符結尾(NULL結束符)的字符數組來存儲的,通常表達為字符指針的形式(char *)。它不允許字節0出現在字符串中間,因此,它不能用來存儲任意的二進制數據。

sds的類型定義

typedef char *sds;

 

每個sds.h/sdshdr結構表示一個SDS的值 
struct sdshdr{ 
//記錄buf數組中已使用的字節的數量 
//等于sds所保存字符串的長度 
int len; 

//記錄buf中未使用的數據 
int free; 

//字符數組,用于保存字符串 
} 


* free 屬性的值為0,表示這個SDS沒有分配任何未使用的空間 
* len 屬性長度為5,表示這個SDS保存一個五字節長的字符串 
* buf 屬性是一個char類型的數組,數組的前5個字節分別保存了'R','e','d','i','s'五個字符,而最后一個字節則保存了空字符串'\0' 

肯定有人感到困惑了,竟然sds就等同于char *?

sds和傳統的C語言字符串保持類型兼容,因此它們的類型定義是一樣的,都是char *,在有些情況下,需要傳入一個C語言字符串的地方,也確實可以傳入一個sds。

但是sds和char *并不等同,sds是Binary Safe的,它可以存儲任意二進制數據,不能像C語言字符串那樣以字符'\0'來標識字符串的結束,因此它必然有個長度字段,這個字段在header中

sds的header結構

/* Note: sdshdr5 is never used, we just access the flags byte directly.
 * However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
 unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
 char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
 uint8_t len; /* used */
 uint8_t alloc; /* excluding the header and null terminator */
 unsigned char flags; /* 3 lsb of type, 5 unused bits */
 char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
 uint16_t len; /* used */
 uint16_t alloc; /* excluding the header and null terminator */
 unsigned char flags; /* 3 lsb of type, 5 unused bits */
 char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
 uint32_t len; /* used */
 uint32_t alloc; /* excluding the header and null terminator */
 unsigned char flags; /* 3 lsb of type, 5 unused bits */
 char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
 uint64_t len; /* used */
 uint64_t alloc; /* excluding the header and null terminator */
 unsigned char flags; /* 3 lsb of type, 5 unused bits */
 char buf[];
};

SDS一共有5種類型的header。目的是節省內存。

一個SDS字符串的完整結構,由在內存地址上前后相鄰的兩部分組成:

  • 一個header。通常包含字符串的長度(len)、最大容量(alloc)和flags。sdshdr5有所不同。
  • 一個字符數組。這個字符數組的長度等于最大容量+1。真正有效的字符串數據,其長度通常小于最大容量。在真正的字符串數據之后,是空余未用的字節(一般以字節0填充),允許在不重新分配內存的前提下讓字符串數據向后做有限的擴展。在真正的字符串數據之后,還有一個NULL結束符,即ASCII碼為0的'\0'字符。這是為了和傳統C字符串兼容。之所以字符數組的長度比最大容量多1個字節,就是為了在字符串長度達到最大容量時仍然有1個字節存放NULL結束符。

除了sdshdr5之外,其它4個header的結構都包含3個字段:

  • len: 表示字符串的真正長度(不包含NULL結束符在內)。
  • alloc: 表示字符串的最大容量(不包含最后多余的那個字節)。
  • flags: 總是占用一個字節。其中的最低3個bit用來表示header的類型。

在各個header的類型定義中,還有幾個需要我們注意的地方:

  • 在各個header的定義中使用了__attribute__ ((packed)),是為了讓編譯器以緊湊模式來分配內存。如果沒有這個屬性,編譯器可能會為struct的字段做優化對齊,在其中填充空字節。那樣的話,就不能保證header和sds的數據部分緊緊前后相鄰,也不能按照固定向低地址方向偏移1個字節的方式來獲取flags字段了。
  • 在各個header的定義中最后有一個char buf[]。我們注意到這是一個沒有指明長度的字符數組,這是C語言中定義字符數組的一種特殊寫法,稱為柔性數組(flexible array member),只能定義在一個結構體的最后一個字段上。它在這里只是起到一個標記的作用,表示在flags字段后面就是一個字符數組,或者說,它指明了緊跟在flags字段后面的這個字符數組在結構體中的偏移位置。而程序在為header分配的內存的時候,它并不占用內存空間。如果計算sizeof(struct sdshdr16)的值,那么結果是5個字節,其中沒有buf字段。
  • sdshdr5與其它幾個header結構不同,它不包含alloc字段,而長度使用flags的高5位來存儲。因此,它不能為字符串分配空余空間。如果字符串需要動態增長,那么它就必然要重新分配內存才行。所以說,這種類型的sds字符串更適合存儲靜態的短字符串(長度小于32)。

至此,我們非常清楚地看到了:sds字符串的header,其實隱藏在真正的字符串數據的前面(低地址方向)。這樣的一個定義,有如下幾個好處:

  • header和數據相鄰,而不用分成兩塊內存空間來單獨分配。這有利于減少內存碎片,提高存儲效率(memory efficiency)。
  • 雖然header有多個類型,但sds可以用統一的char *來表達。且它與傳統的C語言字符串保持類型兼容。如果一個sds里面存儲的是可打印字符串,那么我們可以直接把它傳給C函數,比如使用strcmp比較字符串大小,或者使用printf進行打印。

弄清了sds的數據結構,它的具體操作函數就比較好理解了。

sds的一些基礎函數

  • sdslen(const sds s): 獲取sds字符串長度。
  • sdssetlen(sds s, size_t newlen): 設置sds字符串長度。
  • sdsinclen(sds s, size_t inc): 增加sds字符串長度。
  • sdsalloc(const sds s): 獲取sds字符串容量。
  • sdssetalloc(sds s, size_t newlen): 設置sds字符串容量。
  • sdsavail(const sds s): 獲取sds字符串空余空間(即alloc - len)。
  • sdsHdrSize(char type): 根據header類型得到header大小。
  • sdsReqType(size_t string_size): 根據字符串數據長度計算所需要的header類型。

二、SDS 數組動態分配策略

header信息中的定義這么多字段,其中一個很重要的作用就是實現對字符串的靈活操作并且盡量減少內存重新分配和回收操作。

redis的內存分配策略如下

  • 當SDS的len屬性長度小于1MB時,redis會分配和len相同長度的free空間。至于為什么這樣分配呢,上次用了len長度的空間,那么下次程序可能也會用len長度的空間,所以redis就為你預分配這么多的空間。
  • 但是當SDS的len屬性長度大于1MB時,程序將多分配1M的未使用空間。這個時候我在根據這種慣性預測來分配的話就有點得不償失了。所以redis是將1MB設為一個風險值,沒過風險值你用多少我就給你多少,過了的話那這個風險值就是我能給你臨界值

reids的內存回收策略如下

  • redis的內存回收采用惰性回收,即你把字符串變短了,那么多余的內存空間我先不還給操作系統,先留著,萬一馬上又要被使用呢。短暫的持有資源,既可以充分利用資源,也可以不浪費資源。這是一種很優秀的思想。

綜上所述,redis實現的高性能字符串的結果就把N次字符串操作必會發生N次內存重新分配變為人品最差時最多發生N次重新分配。

/* Enlarge the free space at the end of the sds string so that the caller
 * is sure that after calling this function can overwrite up to addlen
 * bytes after the end of the string, plus one more byte for nul term.
 *
 * Note: this does not change the *length* of the sds string as returned
 * by sdslen(), but only the free buffer space we have. */
sds sdsMakeRoomFor(sds s, size_t addlen) {
 void *sh, *newsh;
 size_t avail = sdsavail(s);
 size_t len, newlen;
 char type, oldtype = s[-1]  SDS_TYPE_MASK;
 int hdrlen;
 
 /* Return ASAP if there is enough space left. */
 if (avail >= addlen) return s;
 
 len = sdslen(s);
 sh = (char*)s-sdsHdrSize(oldtype);
 newlen = (len+addlen);
 if (newlen  SDS_MAX_PREALLOC)
 newlen *= 2;
 else
 newlen += SDS_MAX_PREALLOC;
 
 type = sdsReqType(newlen);
 
 /* Don't use type 5: the user is appending to the string and type 5 is
 * not able to remember empty space, so sdsMakeRoomFor() must be called
 * at every appending operation. */
 if (type == SDS_TYPE_5) type = SDS_TYPE_8;
 
 hdrlen = sdsHdrSize(type);
 if (oldtype==type) {
 newsh = s_realloc(sh, hdrlen+newlen+1);
 if (newsh == NULL) return NULL;
 s = (char*)newsh+hdrlen;
 } else {
 /* Since the header size changes, need to move the string forward,
  * and can't use realloc */
 newsh = s_malloc(hdrlen+newlen+1);
 if (newsh == NULL) return NULL;
 memcpy((char*)newsh+hdrlen, s, len+1);
 s_free(sh);
 s = (char*)newsh+hdrlen;
 s[-1] = type;
 sdssetlen(s, len);
 }
 sdssetalloc(s, newlen);
 return s;
}
 
/* Reallocate the sds string so that it has no free space at the end. The
 * contained string remains not altered, but next concatenation operations
 * will require a reallocation.
 *
 * After the call, the passed sds string is no longer valid and all the
 * references must be substituted with the new pointer returned by the call. */
sds sdsRemoveFreeSpace(sds s) {
 void *sh, *newsh;
 char type, oldtype = s[-1]  SDS_TYPE_MASK;
 int hdrlen;
 size_t len = sdslen(s);
 sh = (char*)s-sdsHdrSize(oldtype);
 
 type = sdsReqType(len);
 hdrlen = sdsHdrSize(type);
 if (oldtype==type) {
 newsh = s_realloc(sh, hdrlen+len+1);
 if (newsh == NULL) return NULL;
 s = (char*)newsh+hdrlen;
 } else {
 newsh = s_malloc(hdrlen+len+1);
 if (newsh == NULL) return NULL;
 memcpy((char*)newsh+hdrlen, s, len+1);
 s_free(sh);
 s = (char*)newsh+hdrlen;
 s[-1] = type;
 sdssetlen(s, len);
 }
 sdssetalloc(s, len);
 return s;
}

三、SDS的特點

sds正是在Redis中被廣泛使用的字符串結構,它的全稱是Simple Dynamic String。與其它語言環境中出現的字符串相比,它具有如下顯著的特點:

  • 可動態擴展內存。SDS表示的字符串其內容可以修改,也可以追加。在很多語言中字符串會分為mutable和immutable兩種,SDS屬于mutable類型的。
  • 二進制安全(Binary Safe)。sds能存儲任意二進制數據。
  • 與傳統的C語言字符串類型兼容。
  • 預分配空間,可以懶惰釋放,在內存緊張的時候也可以縮減不需要的內存
  • 常數復雜度獲取字符串長度
  • 杜絕緩沖區溢出,邊界檢查

四、淺談SDS與string的關系

127.0.0.1:6379> set test test
OK
127.0.0.1:6379> append test " test"
(integer) 9
127.0.0.1:6379> get test
"test test"
127.0.0.1:6379> setbit test 36 1
(integer) 0
127.0.0.1:6379> get test
"test(test"
127.0.0.1:6379> getrange test -5 -1
"(test"
  • append操作使用SDS的sdscatlen來實現。
  • setbit和getrange都是先根據key取到整個sds字符串,然后再從字符串選取或修改指定的部分。由于SDS就是一個字符數組,所以對它的某一部分進行操作似乎都比較簡單。

但是,string除了支持這些操作之外,當它存儲的值是個數字的時候,它還支持incr、decr等操作。它的內部存儲不是SDS,這種情況下,setbit和getrange的實現也會有所不同。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

參考文章

  • http://blog.csdn.net/xiejingfa/article/details/50972592
  • http://blog.csdn.net/acceptedxukai/article/details/17482611
  • https://segmentfault.com/a/1190000003984537
您可能感興趣的文章:
  • Redis底層數據結構詳解
  • 詳解Redis數據結構之跳躍表
  • redis中的數據結構和編碼詳解
  • redis數據結構之intset的實例詳解
  • 詳解redis數據結構之sds
  • 詳解redis數據結構之壓縮列表
  • Redis中5種數據結構的使用場景介紹
  • Redis底層數據結構之dict、ziplist、quicklist詳解

標簽:澳門 景德鎮 揚州 贛州 香港 廣東 唐山 林芝

巨人網絡通訊聲明:本文標題《redis內部數據結構之SDS簡單動態字符串詳解》,本文關鍵詞  redis,內部,數據結構,之,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《redis內部數據結構之SDS簡單動態字符串詳解》相關的同類信息!
  • 本頁收集關于redis內部數據結構之SDS簡單動態字符串詳解的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    东方aⅴ免费观看久久av| 久久日免费视频| 欧美中文字幕亚洲一区二区va在线 | 久久午夜羞羞影院免费观看| 日韩影院精彩在线| 黑森林av导航| 777久久久精品| 亚洲 欧美综合在线网络| 在线观看视频你懂得| 91高清视频免费看| 亚洲激情男女视频| 国产成人精品综合久久久久99| 欧美午夜一区二区三区| 亚洲精品菠萝久久久久久久| 色哟哟在线观看视频| 欧美专区日韩专区| 亚洲第一福利视频在线| 国产真实乱人偷精品| 欧美一级理论片| 婷婷综合另类小说色区| 国产夫妻性爱视频| 精品国产sm最大网站| 精品一区二区国语对白| 国产不卡在线观看视频| 国产精品美女久久久久久久 | 精品91自产拍在线观看一区| 精品一区二区三区在线视频| 国产黄色片在线| 国产精品视频线看| 97久久精品人人爽人人爽蜜臀| 欧美三级在线免费观看| 亚洲激情第一区| 亚洲欧美日韩偷拍| 精品久久久久久久久久久院品网| 狠狠色综合播放一区二区| 国产一区二区三区视频播放| 国产精品久久久久影院色老大| 日韩精品影音先锋| 国产精品自拍一区| 色久优优欧美色久优优| 亚洲777理论| 亚洲一区视频在线播放| 国产精品久久久久久亚洲毛片| 91麻豆视频网站| 日韩美女视频一区二区在线观看| 国产真实乱偷精品视频免| 国内偷拍精品视频| 午夜久久久久久| xxxxx99| 一区二区三区**美女毛片| 中文乱码人妻一区二区三区视频| 久久久久亚洲蜜桃| 99国产精品久久久久| 4438x成人网最大色成网站| 久久不见久久见免费视频1| www色aa色aawww| 天天操天天综合网| fc2ppv在线播放| 亚洲一区av在线| 国产伦理片在线观看| 1区2区3区国产精品| 中文字幕乱码在线| 国产精品水嫩水嫩| 国产精品手机在线观看| 久久久99久久| 欧美性生交xxxxx| 国产三级三级三级精品8ⅰ区| 国产精品无码自拍| 国产日产欧美一区二区三区| 免费黄色av网址| 国产三级欧美三级日产三级99 | 91麻豆免费看片| 久久久精品免费免费| 日本少妇激三级做爰在线| 久久众筹精品私拍模特| 性折磨bdsm欧美激情另类| 国产视频三区四区| 夜夜精品视频一区二区| 欧美激情 一区| 美女免费视频一区二区| 久久免费看少妇高潮v片特黄| 五月综合激情日本mⅴ| 蜜桃av.com| 日本人妖一区二区| 色婷婷综合久久久久中文一区二区| 老汉av免费一区二区三区 | 国产精品青草久久| www.超碰97| 亚洲一区二区三区激情| 日本不卡一二区| 蜜乳av一区二区| 欧美日韩一区二区三区高清| 国产精品原创巨作av| 91精品麻豆日日躁夜夜躁| 成人av网站免费| 久久精品免费在线观看| 人体私拍套图hdxxxx| 一区二区三区四区精品在线视频| 2014亚洲天堂| 九一九一国产精品| 欧美电视剧在线看免费| 精品无码人妻少妇久久久久久| 中文字幕中文字幕在线一区| 国产成人免费观看网站| 视频一区国产视频| 欧美日韩在线综合| www.性欧美| 国产精品国产馆在线真实露脸| 日本一级免费视频| 日韩**一区毛片| 91精品免费在线| 好吊操视频这里只有精品| 亚洲欧洲综合另类| 一本色道久久综合精品竹菊| 国产成人免费视频精品含羞草妖精| 精品国产sm最大网站免费看 | 中文字幕在线观看免费高清| 日日摸夜夜添夜夜添精品视频| 欧美日韩亚洲综合一区二区三区| jiyouzz国产精品久久| 国产精品视频第一区| 国产亚洲精品熟女国产成人| 日日夜夜精品免费视频| 欧美日韩一本到| 午夜剧场免费看| 天堂成人国产精品一区| 欧美精品 国产精品| 97中文字幕在线观看| 亚洲一区二区三区四区中文字幕| 欧美在线你懂得| 亚洲AV无码久久精品国产一区| 一区二区视频在线看| 欧洲在线/亚洲| 制服.丝袜.亚洲.中文.综合懂| 一区二区激情小说| 欧美精品成人一区二区三区四区| 最新版天堂资源在线| 亚洲成a天堂v人片| 欧美一三区三区四区免费在线看 | 国产一区二区导航在线播放| 久久久精品中文字幕麻豆发布| 人妻一区二区视频| 国产一区二区免费在线| 欧美激情在线看| 在线日韩一区二区| 欧美图片自拍偷拍| 免费精品99久久国产综合精品| 精品国产伦一区二区三区观看体验 | 97人妻精品一区二区免费| 国产真实乱子伦精品视频| 中文av一区二区| 色久优优欧美色久优优| 9.1在线观看免费| 免费看欧美女人艹b| 久久嫩草精品久久久精品 | 久久精品国产色蜜蜜麻豆| 国产亚洲欧美色| avtt天堂在线| 污网站免费观看| 久久精品国产精品亚洲红杏| 日本一区二区免费在线观看视频 | 一区二区三区在线视频播放| 欧美精品aⅴ在线视频| jizz中文字幕| 不卡的电影网站| 性久久久久久久久| 久久久亚洲综合| 色偷偷久久人人79超碰人人澡| www.四虎在线| 国产麻豆日韩欧美久久| 亚洲人成在线观看一区二区| 欧美一级在线观看| 99久久久免费精品| wwwxxx色| 国产一区二区调教| 亚洲精品videosex极品| 日韩欧美二区三区| 亚洲精品卡一卡二| 秘密基地免费观看完整版中文 | 久久97超碰国产精品超碰| 国产精品美女久久久久久久久| 欧美剧在线免费观看网站| 欧美成人另类视频| 日本黄色一级网站| 久久99热这里只有精品| 亚洲色大成网站www久久九九| 欧美一级艳片视频免费观看| 搜索黄色一级片| 无码人妻aⅴ一区二区三区| 成人美女在线观看| 美女任你摸久久| 亚洲六月丁香色婷婷综合久久 | 日韩午夜中文字幕| 色婷婷亚洲婷婷| 一级黄色录像毛片| 美女露出粉嫩尿囗让男人桶| 国产成人综合网| 男女视频一区二区| 一区二区在线看| 国产日产欧美一区|