1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Redis 的字符串是如何實(shí)現(xiàn)的?

        共 1937字,需瀏覽 4分鐘

         ·

        2020-09-06 19:18

        作者:巔峰大詞典
        來(lái)源:SegmentFault思否社區(qū)



        東邊日出西邊雨,道是無(wú)晴卻有晴。

        本篇會(huì)講以下內(nèi)容:

        • Redis字符串的實(shí)現(xiàn)
        • Redis字符串的性能優(yōu)勢(shì)

        Redis字符串的實(shí)現(xiàn)

        Redis雖然是用C語(yǔ)言寫(xiě)的,但卻沒(méi)有直接用C語(yǔ)言的字符串,而是自己實(shí)現(xiàn)了一套字符串。目的就是為了提升速度,提升性能,可以看出Redis為了高性能也是煞費(fèi)苦心。

        Redis構(gòu)建了一個(gè)叫做簡(jiǎn)單動(dòng)態(tài)字符串(Simple Dynamic String),簡(jiǎn)稱(chēng)SDS

        1.SDS 代碼結(jié)構(gòu)

        struct?sdshdr{
        ????//??記錄已使用長(zhǎng)度
        ????int?len;
        ????//?記錄空閑未使用的長(zhǎng)度
        ????int?free;
        ????//?字符數(shù)組
        ????char[]?buf;
        };

        SDS ?什么鬼?可能對(duì)此陌生的朋友對(duì)這個(gè)名稱(chēng)有疑惑。只是個(gè)名詞而已不必在意,我們要重點(diǎn)欣賞借鑒Redis的設(shè)計(jì)思路。下面畫(huà)個(gè)圖來(lái)說(shuō)明,一目了然。image

        Redis的字符串也會(huì)遵守C語(yǔ)言的字符串的實(shí)現(xiàn)規(guī)則,即最后一個(gè)字符為空字符。然而這個(gè)空字符不會(huì)被計(jì)算在len里頭。

        2.SDS 動(dòng)態(tài)擴(kuò)展特點(diǎn)

        SDS的最厲害最奇妙之處在于它的Dynamic。動(dòng)態(tài)變化長(zhǎng)度。舉個(gè)例子

        如上圖所示剛開(kāi)始s1 只有5個(gè)空閑位子,后面需要追加' world' 6個(gè)字符,很明顯是不夠的。那咋辦?Redis會(huì)做以下三個(gè)操作:

        • 計(jì)算出大小是否足夠
        • 開(kāi)辟空間至滿(mǎn)足所需大小
        • 開(kāi)辟與已使用大小len相同長(zhǎng)度的空閑free空間(如果len < 1M)開(kāi)辟1M長(zhǎng)度的空閑free空間(如果len >= 1M)

        看到這兒為止有沒(méi)有朋友覺(jué)得這個(gè)實(shí)現(xiàn)跟Java的列表List實(shí)現(xiàn)有點(diǎn)類(lèi)似呢?看完后面的會(huì)覺(jué)得更像了。

        Redis字符串的性能優(yōu)勢(shì)

        • 快速獲取字符串長(zhǎng)度
        • 避免緩沖區(qū)溢出
        • 降低空間分配次數(shù)提升內(nèi)存使用效率

        1.快速獲取字符串長(zhǎng)度

        再看下上面的SDS結(jié)構(gòu)體:

        struct?sdshdr{
        ????//??記錄已使用長(zhǎng)度
        ????int?len;
        ????//?記錄空閑未使用的長(zhǎng)度
        ????int?free;
        ????//?字符數(shù)組
        ????char[]?buf;
        };

        由于在SDS里存了已使用字符長(zhǎng)度len,所以當(dāng)想獲取字符串長(zhǎng)度時(shí)直接返回len即可,時(shí)間復(fù)雜度為O(1)。如果使用C語(yǔ)言的字符串的話它的字符串長(zhǎng)度獲取函數(shù)時(shí)間復(fù)雜度為O(n),n為字符個(gè)數(shù),因?yàn)樗菑念^到尾(到空字符'\0')遍歷相加。

        2.避免緩沖區(qū)溢出

        對(duì)一個(gè)C語(yǔ)言字符串進(jìn)行strcat追加字符串的時(shí)候需要提前開(kāi)辟需要的空間,如果不開(kāi)辟空間的話可能會(huì)造成緩沖區(qū)溢出,而影響程序其他代碼。如下圖,有一個(gè)字符串s1="hello" 和 字符串s2="baby",現(xiàn)在要執(zhí)行strcat(s1,"world"),并且執(zhí)行前未給s1開(kāi)辟空間,所以造成了緩沖區(qū)溢出。

        而對(duì)于Redis而言由于每次追加字符串時(shí)都會(huì)檢查空間是否夠用,所以不會(huì)存在緩沖區(qū)溢出問(wèn)題。每次追加操作前都會(huì)做如下操作:

        • 計(jì)算出大小是否足夠
        • 開(kāi)辟空間至滿(mǎn)足所需大小

        3.降低空間分配次數(shù)提升內(nèi)存使用效率

        字符串的追加操作會(huì)涉及到內(nèi)存分配問(wèn)題,然而內(nèi)存分配問(wèn)題會(huì)牽扯內(nèi)存劃分算法以及系統(tǒng)調(diào)用所以如果頻繁發(fā)生的話影響性能,所以對(duì)于性能至上的Redis來(lái)說(shuō)這是萬(wàn)萬(wàn)不能忍受的。所以采取了以下兩種優(yōu)化措施

        • 空間與分配
        • 惰性空間回收

        1. 空間預(yù)分配

        對(duì)于追加操作來(lái)說(shuō),Redis不僅會(huì)開(kāi)辟空間至夠用而且還會(huì)預(yù)分配未使用的空間(free)來(lái)用于下一次操作。至于未使用的空間(free)的大小則由修改后的字符串長(zhǎng)度決定。

        當(dāng)修改后的字符串長(zhǎng)度len < 1M,則會(huì)分配與len相同長(zhǎng)度的未使用的空間(free)

        當(dāng)修改后的字符串長(zhǎng)度len >= 1M,則會(huì)分配1M長(zhǎng)度的未使用的空間(free)

        有了這個(gè)預(yù)分配策略之后會(huì)減少內(nèi)存分配次數(shù),因?yàn)榉峙渲皶?huì)檢查已有的free空間是否夠,如果夠則不開(kāi)辟了~

        2. 惰性空間回收

        與上面情況相反,惰性空間回收適用于字符串縮減操作。比如有個(gè)字符串s1="hello world",對(duì)s1進(jìn)行sdstrim(s1," world")操作,執(zhí)行完該操作之后Redis不會(huì)立即回收減少的部分,而是會(huì)分配給下一個(gè)需要內(nèi)存的程序。當(dāng)然,Redis也提供了回收內(nèi)存的api,可以自己手動(dòng)調(diào)用來(lái)回收縮減部分的內(nèi)存。

        到此為止結(jié)束了~




        點(diǎn)擊左下角閱讀原文,到?SegmentFault 思否社區(qū)?和文章作者展開(kāi)更多互動(dòng)和交流。

        -?END -

        瀏覽 37
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            99热热久久| 《年轻女教师3》在线hd h荡肉呻吟男男动漫 | 免费xxxx | 国产激情在线 | 青娱乐超碰在线 | 大美女swag | 全部裸体电影战争片 | 玖玖在线免费视频 | 狠狠躁夜夜躁人人 | 欧美XXXxXX高潮喷水 |