Netty源碼(一):Netty中的Buffer

最近我學(xué)習(xí)了NIO相關(guān)的知識(shí),然后發(fā)現(xiàn)了Netty這個(gè)基于NIO的網(wǎng)絡(luò)應(yīng)用框架,于是就研究起Netty框架源碼,來(lái)好好體會(huì)一下網(wǎng)絡(luò)框架的設(shè)計(jì)理念和思想.
?這個(gè)系列的文章不僅會(huì)總結(jié)Netty各個(gè)模塊的源碼原理,也會(huì)寫出一些自己對(duì)這些設(shè)計(jì)的理解和體會(huì).
?我基本按照并發(fā)編程網(wǎng)上這個(gè)系列文章的順序來(lái)進(jìn)行系列文章的順序,不同的是我是基于Netty4.1的源碼進(jìn)行分析和講解.
?為了節(jié)約你的時(shí)間,本篇文章主要內(nèi)容如下:

  • Netty的Buffer的內(nèi)存模型,涉及讀寫指針
  • Netty的Buffer框架
  • Netty的Pool原理,輕量對(duì)象池

Buffer

Java NIO中的Buffer用于和NIO通道進(jìn)行交互,數(shù)據(jù)可以從通道讀入緩沖區(qū),也可以從緩沖區(qū)寫入到通道中.所以說(shuō),Buffer其實(shí)就是一塊可以讀寫數(shù)據(jù)的內(nèi)存,我們將其包裝為一個(gè)Java對(duì)象來(lái)提供一系列讀寫操作.
?Netty并沒(méi)有直接使用Java NIO的Buffer實(shí)現(xiàn),而是自己實(shí)現(xiàn)了一套Buffer框架來(lái)滿足自己的業(yè)務(wù)或者性能需求.

ByteBuf的基本原理

讀寫指針的作用

不同于NIO Buffer的讀寫指針共用原理,ByteBuf擁有readerIndex,writerIndex兩個(gè)指針.下面我們就來(lái)詳細(xì)的講解一下ByteBuf的內(nèi)部原理.

     +-------------------+------------------+------------------+
     | discardable bytes |  readable bytes  |  writable bytes  |
     |                   |     (CONTENT)    |                  |
     +-------------------+------------------+------------------+
     |                   |                  |                  |
     0      <=      readerIndex   <=   writerIndex    <=    capacity

從示意圖中我們可以看出readerIndexwriterIndex最多可以將整個(gè)內(nèi)容空間劃分為三塊:廢棄區(qū),可讀區(qū)可寫區(qū).下面我們就來(lái)看一下不同操作下的兩個(gè)指針的變化.

  • 在初始化狀態(tài)下,假設(shè)capacity為20,readerIndexwriterIndex都為0,整個(gè)空間中只存在可寫區(qū).此時(shí)只能寫,不能讀,進(jìn)行讀操作會(huì)拋出異常.
       +---------------------------------------------------------+
       |             writable bytes (got more space)             |
       +---------------------------------------------------------+
       |                                                         |
 readerIndex(0)
  writerIndex(0)                   <=                   capacity
  • 寫入10個(gè)字節(jié)的數(shù)據(jù),writerIndex指向10,readerIndex不會(huì)改變,所有內(nèi)容空間中有可讀區(qū)和可寫區(qū).大小都是10字節(jié).
       +-------------------+------------------+------------------+
       |  readable bytes  |  writable bytes                      |
       |     (CONTENT)    |                                      |
       +--------- --------+------------------+------------------
       |                  |                                      |
     readerIndex(0) <= writerIndex(10)           <=        capacity
  • 讀取5個(gè)字節(jié)的內(nèi)容,writerIndex不變,readerIndex加5,指向了5.此時(shí)內(nèi)容空間分為了5字節(jié)的廢棄區(qū),5字節(jié)的可讀區(qū)和10字節(jié)的可寫區(qū).

 +-------------------+------------------+------------------+
 | discardable bytes |  readable bytes  |  writable bytes  |
 |                   |     (CONTENT)    |                  |
 +-------------------+------------------+------------------+
 |                   |                  |                  |
 0      <=      readerIndex(5)   <=   writerIndex(10)    <=  capacity
  • 調(diào)用discardReadBytes方法后,將廢棄區(qū)的內(nèi)容舍棄掉,readerIndex又指向了0,writerIndex指向了5,相當(dāng)于可讀區(qū)和可寫區(qū)整體向左平移了5個(gè)字節(jié).
       +------------------+--------------------------------------+
       |  readable bytes  |    writable bytes (got more space)   |
       +------------------+--------------------------------------+
       |                  |                                      |
  readerIndex (0) <= writerIndex (5)              <=        capacity

零拷貝

OS層次上Zero-copy,就是在操作數(shù)據(jù)時(shí),不需要將數(shù)據(jù)buffer從一個(gè)內(nèi)存區(qū)域拷貝到另一個(gè)內(nèi)存區(qū)域,因?yàn)闇p少了一次內(nèi)存的拷貝,因此CPU的效率得到了提升.
?Nettyzero-copy體現(xiàn)在很多方面.比如Buffer的compose,duplicate,slice操作時(shí)不會(huì)拷貝底層的數(shù)據(jù).而是通過(guò)ByteBuf對(duì)象的組合來(lái)實(shí)現(xiàn)上述的操作

  • Netty提供了CompositeByteBuf類,可以將多個(gè)ByteBuf組合成一個(gè)邏輯上的Buffer,避免了各個(gè)buffer之間的拷貝,CompositeByteBuf并不擁有底層的數(shù)據(jù),而是通過(guò)擁有兩個(gè)buffer對(duì)象,從這兩個(gè)buffer對(duì)象中獲取數(shù)據(jù)來(lái)對(duì)外提供看似合并了的數(shù)據(jù).比如我們將一份協(xié)議數(shù)據(jù)的頭部buffer和消息體buffer合并成一個(gè)Buffer.

    1495838149-5833cca6c5c3d_articlex.png

    ?如上圖所示,所有底層的數(shù)據(jù)還是存儲(chǔ)在header和body這兩個(gè)真實(shí)的buffer中.

  • 對(duì)于ByteBufsliceduplicate操作也是如此,不同的buffer共享了相同的底層數(shù)據(jù),而不是進(jìn)行底層數(shù)據(jù)的拷貝.具體使用到的Buffer類型為DuplicatedByteBufSlicedByteBuf.誰(shuí)說(shuō)是共享的底層數(shù)據(jù),但是通過(guò)對(duì)writerIndexreaderIndex兩個(gè)指針的操作來(lái)實(shí)現(xiàn)slice和duplicate的功能.

  • Netty使用wrap操作將byte數(shù)組轉(zhuǎn)化為ByteBuf對(duì)象時(shí),將byte數(shù)組包裹到對(duì)象中,而不是拷貝數(shù)組存放到對(duì)象中.

  • Netty 中使用 FileRegion 實(shí)現(xiàn)文件傳輸?shù)牧憧截? 不過(guò)在底層 FileRegion 是依賴于 Java NIO FileChannel.transfer 的零拷貝功能.

Pool和Reference Count

4.0之后的版本實(shí)現(xiàn)了高性能的Buffer池,分配策略則是結(jié)合了buddy allocation和slab allocation的jemalloc變種祠饺,實(shí)現(xiàn)類為PoolArena,這樣的話,可以在頻繁分配和釋放Buffer時(shí)緩解GC壓力,還可以在初始化新buffer時(shí)減少內(nèi)存帶寬消耗(初始化時(shí)不可避免的要給buffer數(shù)組賦初始值).
?ByteBuf引入了Reference Count機(jī)制,你需要在不適用它的時(shí)候調(diào)用ReferenceCountUtil.release方法來(lái)減少它的引用.

后記

?感覺(jué)自己在研究或在閱讀源代碼時(shí)還是有些問(wèn)題,起始ByteBuf并不是Netty的關(guān)鍵所在,不應(yīng)該花費(fèi)這么長(zhǎng)時(shí)間.以后還是要帶著目的來(lái)看源碼,不能把時(shí)間浪費(fèi)在一些代碼細(xì)節(jié)上.

引用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夕土,隨后出現(xiàn)的幾起案子官扣,更是在濱河造成了極大的恐慌邪码,老刑警劉巖宾尚,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孝情,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡著恩,警方通過(guò)查閱死者的電腦和手機(jī)院尔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喉誊,“玉大人邀摆,你說(shuō)我怎么就攤上這事∥榍眩” “怎么了栋盹?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)敷矫。 經(jīng)常有香客問(wèn)我例获,道長(zhǎng),這世上最難降的妖魔是什么曹仗? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任榨汤,我火速辦了婚禮,結(jié)果婚禮上整葡,老公的妹妹穿的比我還像新娘件余。我一直安慰自己讥脐,他們只是感情好遭居,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布啼器。 她就那樣靜靜地躺著,像睡著了一般俱萍。 火紅的嫁衣襯著肌膚如雪端壳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天枪蘑,我揣著相機(jī)與錄音损谦,去河邊找鬼。 笑死岳颇,一個(gè)胖子當(dāng)著我的面吹牛照捡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播话侧,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼栗精,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了瞻鹏?” 一聲冷哼從身側(cè)響起悲立,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎新博,沒(méi)想到半個(gè)月后薪夕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赫悄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年原献,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涩蜘。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嚼贡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出同诫,到底是詐尸還是另有隱情粤策,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布误窖,位于F島的核電站叮盘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏霹俺。R本人自食惡果不足惜柔吼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丙唧。 院中可真熱鬧愈魏,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至牌柄,卻和暖如春畸悬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背珊佣。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工蹋宦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咒锻。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓冷冗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親惑艇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贾惦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容