Netty的ByteBuf是JDK中ByteBuffer的升級(jí)版,提供了NIO buffer和byte數(shù)組的抽象視圖。
ByteBuf的主要類集成關(guān)系:
(圖片來(lái)自Netty權(quán)威指南,圖中有一個(gè)畫錯(cuò)的地方是PooledByteBuf中的最后一個(gè)子類應(yīng)該是PooledUnsafeDirectByteBuf)
從繼承關(guān)系可以看出AbstractReferenceCountedByteBuf的子類分為兩類:Pooled和Unpooled的ByteBuf。
Pooled ByteBuf是基于對(duì)象池的ByteBuf(會(huì)被緩存),Unpooled則是普通的ByteBuf對(duì)象。
無(wú)論是否基于內(nèi)存池的ByteBuf,它的子類有分為DirectByteBuf和HeapByteBuf分別表示在堆外內(nèi)存分配的緩沖區(qū)和在堆內(nèi)存的緩沖區(qū)。
堆內(nèi)存緩沖區(qū)的特點(diǎn)是分配和回收速度快,可以被JVM自動(dòng)回收;缺點(diǎn)是如果進(jìn)行Socket的IO讀寫,需要額外做一次內(nèi)存復(fù)制。
堆外內(nèi)存的緩沖區(qū)相對(duì)于堆內(nèi)存的緩沖區(qū),分配和回收的速度會(huì)慢一些,但是將它寫入或從Socket Channel讀取數(shù)據(jù)是,會(huì)少一次內(nèi)存復(fù)制,速度比堆內(nèi)存更快一些。
BufferBuf也提供了一類API來(lái)將自己轉(zhuǎn)化成為ByteBuffer以便于在需要ByteBuffer的地方進(jìn)行操作。
AbstractByteBuf
AbstractByteBuf定義了ByteBuf的基礎(chǔ)屬性和一些公用的方法。
主要成員變量有:
readerIndex
writerIndex
markedReaderIndex
markedWriterIndex
maxCapacity
可以看到ByteBuf中分別定義了讀寫游標(biāo),也就是說(shuō)讀游標(biāo)和寫游標(biāo)是分離的,這相對(duì)于ByteBuffer只使用一個(gè)position,在讀寫操作時(shí)會(huì)便利很多。
一塊緩沖區(qū)會(huì)被兩個(gè)游標(biāo)分隔為三塊區(qū)域,分別是已經(jīng)讀取過(guò)的、可讀的、剩余可寫的。
在寫入數(shù)據(jù)后可以直接開始讀取,不需要flip操作。
另外AbstractByteBuf中的方法分為三類:
讀取數(shù)據(jù)、寫入數(shù)據(jù)、操作游標(biāo)
讀取操作分為readXXX和getXXX,以讀取Long為例,
readLong()方法在當(dāng)前readerIndex位置讀取8個(gè)Byte并增加readerindex的值;
getLong(int index)則需要接收一個(gè)index參數(shù),從index位置開始讀取8個(gè)Byte,get操作不會(huì)改變r(jià)eaderIndex的值。
寫入操作也有兩類,分別是setXXX和writeXXX,
writeLong(long value)方法在當(dāng)前writerIndex位置開始寫入一個(gè)Long值并增加writerIndex的值;
setLong(int index, long value)方法則接收一個(gè)index參數(shù)作為寫入的位置,寫入操作不修改writerIndex的值。
索引操作就是通過(guò)setReaderIndex之類的方法改變r(jià)eaderIndex的值來(lái)重新讀取數(shù)據(jù),非常簡(jiǎn)單,不做說(shuō)明。
AbstractReferenceCountedByteBuf
從類名上看,AbstractReferenceCountedByteBuf主要是實(shí)現(xiàn)了對(duì)引用的計(jì)數(shù),類似于JVM內(nèi)存回收的對(duì)象引用計(jì)數(shù)器,用于跟蹤對(duì)象的分配和銷毀。
只有一個(gè)成員變量:refCnt,看命名也知道是用于計(jì)數(shù)的,并且用AtomicIntegerFieldUpdater來(lái)實(shí)現(xiàn)線程安全的計(jì)數(shù)。
retain API用于增加引用的計(jì)數(shù)。
release則用于減少計(jì)數(shù)值。
定義deallocate方法讓子類去實(shí)現(xiàn)當(dāng)引用計(jì)數(shù)為0時(shí)的操作(由子類實(shí)現(xiàn)具體的“回收”操作)。
UnpooledHeapByteBuffer
UnpooledHeapByteBuffer是不適用對(duì)象池,且直接在堆內(nèi)存上分配的緩沖區(qū)。
ByteBufAllocator alloc:創(chuàng)建了這個(gè)緩沖區(qū)的分配器
byte[] array:底層存儲(chǔ)
ByteBuffer tmpNioBuf:Nio ByteBuffer對(duì)象,用于將自身轉(zhuǎn)換成一個(gè)ByteBuffer對(duì)象
構(gòu)造方法非常簡(jiǎn)單:
記錄分配器alloc;
初始化數(shù)組;
將讀寫位置調(diào)整為0;
這個(gè)構(gòu)造方法則是傳入byte數(shù)組做初始化,writerIndex調(diào)整到數(shù)組后的第一個(gè)位置。
兩個(gè)構(gòu)造方法都有maxCapacity參數(shù),且初始容量要么是initialCapacity要么是initalArray的長(zhǎng)度,說(shuō)明緩沖區(qū)的大小是可以調(diào)整的,最大不超過(guò)maxCapacity。
通過(guò)capacity來(lái)調(diào)整緩沖區(qū)的大小。如果newCapacity小于當(dāng)前array的length,那么會(huì)有部分?jǐn)?shù)據(jù)被丟棄。如果newCapacity超過(guò)array的length,那么新擴(kuò)容的位置數(shù)據(jù)未空。
UnpooledDirectByteBuf
ByteBufAllocator alloc:使用的分配器
ByteBuffer buffer:內(nèi)部用于存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)
ByteBuffer tmpNioBuf:臨時(shí)的ByteBuffer,在將自己轉(zhuǎn)換成ByteBuffer對(duì)象時(shí)會(huì)使用
int capacity:容量
doNotFree:標(biāo)志ByteBuffer是否可以回收
區(qū)別于UnpooledHeapByteBuf,UnpooledDirectByteBuf的擴(kuò)容操作不在是申請(qǐng)數(shù)組進(jìn)行數(shù)據(jù)拷貝,而是申請(qǐng)新的ByteBuffer之后進(jìn)行收拷貝,而ByteBuffer一定是Direct的。
deallocate實(shí)現(xiàn)了底層存儲(chǔ)ByteBuffer的回收操作,即在引用計(jì)數(shù)為0時(shí)將DirectByteBuffer回收掉(DirectByteBuffer的內(nèi)存是由自己回收的,而不是JVM)。
UnpooledUnsafeDirectByteBuf
UnpooledUnsafeDirectByteBuf和UnpooledUnsafeDirectByteBuf的區(qū)別在于UnpooledUnsafeDirectByteBuf直接使用ByteBuffer來(lái)操作數(shù)據(jù),而UnpooledUnsafeDirectByteBuf采用Unsafe來(lái)操作數(shù)據(jù)。
UnpooledUnsafeDirectByteBuf的_getLong實(shí)現(xiàn):
UnpooledUnsafeDirectByteBuf的_getLong實(shí)現(xiàn):
AbstractReferenceCountedByteBuf子類的另一個(gè)分支是PooledByteBuf,即使用對(duì)象池,會(huì)被緩存的ByteBuffer。
PooledByteBuf有三個(gè)子類:
PooledHeapByteBuf
PooledDirectByteBuf
PooledUnsafeDirectByteBuf
他們分別和Unpooled的幾個(gè)子類對(duì)應(yīng)。
對(duì)于Pooled的實(shí)現(xiàn),詳見Netty對(duì)象池實(shí)現(xiàn)分析。
歡迎關(guān)注我的個(gè)人公眾號(hào),會(huì)寫一些列關(guān)于消息中間件的文章,也歡迎交流任何技術(shù)問(wèn)題,或者扯扯淡。
http://www.cnblogs.com/hzmark/p/Netty_ByteBuf.html