<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【32期】你知道Redis的字符串是怎么實(shí)現(xiàn)的嗎?

          共 2542字,需瀏覽 6分鐘

           ·

          2020-09-10 23:34

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 4 分鐘。

          來自:juejin.im/post/5ca9d8ae6fb9a05e5c05c4e8

          之前本人在找工作面試時(shí)在Redis相關(guān)問題上可栽了跟頭。在面試前按常規(guī)套路準(zhǔn)備了一下,比如 Redis 的常用5種數(shù)據(jù)結(jié)構(gòu),Redis持久化策略,Redis實(shí)現(xiàn)分布式鎖,簡單發(fā)布訂閱等等都準(zhǔn)備了,當(dāng)時(shí)不知天高地厚以為十拿九穩(wěn)了,可是萬萬沒想到我終究還是在Redis的被問的第一個(gè)問題上翻船了~~
          面試官 :看你簡歷上寫了熟悉常用數(shù)據(jù)結(jié)構(gòu),都有哪些說說
          本人 :常用有5種,string,list,set,zset,hash(內(nèi)心很得意)
          面試官 :那你說說都用過哪些數(shù)據(jù)結(jié)構(gòu)
          本人 :用的最多的是string,通常會把json字符串存進(jìn)去
          面試官 :那你知道Redis內(nèi)部是怎么實(shí)現(xiàn)它的string的么?
          本人 :呃~,我了解Redis是用C語言寫的,至于具體實(shí)現(xiàn)就不清楚了~
          到此一面卒~~~
          有相同經(jīng)歷的朋友么?

          回去后惡補(bǔ)了一下Redis有關(guān)原理性的知識點(diǎn),恰好最近在最總結(jié)面試經(jīng)歷于是有了今天這篇文章。
          本篇會講以下內(nèi)容:
          • Redis字符串的實(shí)現(xiàn)

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

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

          Redis雖然是用C語言寫的,但卻沒有直接用C語言的字符串,而是自己實(shí)現(xiàn)了一套字符串。目的就是為了提升速度,提升性能,可以看出Redis為了高性能也是煞費(fèi)苦心。
          Redis構(gòu)建了一個(gè)叫做簡單動態(tài)字符串(Simple Dynamic String),簡稱SDS

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

          struct?sdshdr{
          ????//??記錄已使用長度
          ????int?len;
          ????//?記錄空閑未使用的長度
          ????int?free;
          ????//?字符數(shù)組
          ????char[]?buf;
          };
          SDS ?什么鬼?可能對此陌生的朋友對這個(gè)名稱有疑惑。只是個(gè)名詞而已不必在意,我們要重點(diǎn)欣賞借鑒Redis的設(shè)計(jì)思路。下面畫個(gè)圖來說明,一目了然。
          Redis的字符串也會遵守C語言的字符串的實(shí)現(xiàn)規(guī)則,即最后一個(gè)字符為空字符。然而這個(gè)空字符不會被計(jì)算在len里頭。

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

          SDS的最厲害最奇妙之處在于它的Dynamic。動態(tài)變化長度。舉個(gè)例子
          如上圖所示剛開始s1 只有5個(gè)空閑位子,后面需要追加' world' 6個(gè)字符,很明顯是不夠的。那咋辦?Redis會做下三個(gè)操作:
          1. 計(jì)算出大小是否足夠

          2. 開辟空間至滿足所需大小

          3. 開辟與已使用大小len相同長度的空閑free空間(如果len < 1M)開辟1M長度的空閑free空間(如果len >= 1M)

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

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

          • 快速獲取字符串長度

          • 避免緩沖區(qū)溢出

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

          1.快速獲取字符串長度

          看下上面的SDS結(jié)構(gòu)體:
          struct?sdshdr{
          ????//??記錄已使用長度
          ????int?len;
          ????//?記錄空閑未使用的長度
          ????int?free;
          ????//?字符數(shù)組
          ????char[]?buf;
          };
          由于在SDS里存了已使用字符長度len,所以當(dāng)想獲取字符串長度時(shí)直接返回len即可,時(shí)間復(fù)雜度為O(1)。如果使用C語言的字符串的話它的字符串長度獲取函數(shù)時(shí)間復(fù)雜度為O(n),n為字符個(gè)數(shù),因?yàn)樗菑念^到尾(到空字符'\0')遍歷相加。

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

          對一個(gè)C語言字符串進(jìn)行strcat追加字符串的時(shí)候需要提前開辟需要的空間,如果不開辟空間的話可能會造成緩沖區(qū)溢出,而影響程序其他代碼。如下圖,有一個(gè)字符串s1="hello" 和 字符串s2="baby",現(xiàn)在要執(zhí)行strcat(s1,"world"),并且執(zhí)行前未給s1開辟空間,所以造成了緩沖區(qū)溢出。
          而對于Redis而言由于每次追加字符串時(shí)都會檢查空間是否夠用,所以不會存在緩沖區(qū)溢出問題。每次追加操作前都會做如下操作:
          1. 計(jì)算出大小是否足夠

          2. 開辟空間至滿足所需大小

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

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

          • 惰性空間回收

          1. 空間預(yù)分配
          對于追加操作來說,Redis不僅會開辟空間至夠用而且還會預(yù)分配未使用的空間(free)來用于下一次操作。至于未使用的空間(free)的大小則由修改后的字符串長度決定。
          當(dāng)修改后的字符串長度len < 1M,則會分配與len相同長度的未使用的空間(free)
          當(dāng)修改后的字符串長度len >= 1M,則會分配1M長度的未使用的空間(free)
          有了這個(gè)預(yù)分配策略之后會減少內(nèi)存分配次數(shù),因?yàn)榉峙渲皶z查已有的free空間是否夠,如果夠則不開辟了~
          2. 惰性空間回收
          與上面情況相反,惰性空間回收適用于字符串縮減操作。比如有個(gè)字符串s1="hello world",對s1進(jìn)行sdstrim(s1," world")操作,執(zhí)行完該操作之后Redis不會立即回收減少的部分,而是會分配給下一個(gè)需要內(nèi)存的程序。當(dāng)然,Redis也提供了回收內(nèi)存的api,可以自己手動調(diào)用來回收縮減部分的內(nèi)存。
          到此為止結(jié)束了~
          下次在遇到這個(gè)問題可以侃侃而談了,哈哈哈

          推薦閱讀:

          【31期】了解什么是 redis 的雪崩、穿透和擊穿?redis 崩潰之后會怎么樣?應(yīng)對措施是什么

          【30期】說一下HashMap的實(shí)現(xiàn)原理?

          【29期】Java集合框架 10 連問,你有被問過嗎?

          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹莓派,等等。在公眾號內(nèi)回復(fù)「2048」,即可免費(fèi)獲取!!

          微信掃描二維碼,關(guān)注我的公眾號

          寫留言

          朕已閱?

          瀏覽 64
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本不卡视屏 | 激情小视频 | www草逼 | 久久性爱视屏 | AV-ThePorn |