天天看點

Netty入門(一):ByteBuf

       網絡資料的基本機關總是位元組。Java NIO 提供了 ByteBuffer 作為它的位元組容器,但是這個類使用起來過于複雜,而且也有些繁瑣。Netty 的 ByteBuffer 替代品是 ByteBuf,一個強大的實作,既解決了 JDK API 的局限性,又為網絡應用程式的開發者提供了更好的 API

ByteBuf優勢

  • 它可以被使用者自定義的緩沖區類型擴充
  • 通過内置的複合緩沖區類型實作了透明的零拷貝
  • 容量可以按需增長
  • 在讀和寫這兩種模式之間切換不需要調用 ByteBuffer 的 flip()方法
  • 讀和寫使用了不同的索引
  • 支援方法的鍊式調用
  • 支援引用計數
  • 支援池化

ByteBuf實作原理

Netty入門(一):ByteBuf

如圖ByteBuf通維護了兩個不同的索引:一個用于讀取,一個用于寫入。

當你從 ByteBuf 讀取時,它的 readerIndex 将會被遞增已經被讀取的位元組數。同樣地,當你寫入 ByteBuf 時,它的writerIndex 也會被遞增

Netty入門(一):ByteBuf

當調用readBytes時,readIndex會相應移動length位,如果readIndex移動後大于writeIndex則會抛異常。

Netty入門(一):ByteBuf

當調用writeBytes時,writeIndex會相應移動length位,且通過ensureWritable方法實作自動擴容

其他常用API

getBytes 擷取可讀位元組數組
setBytes 寫入位元組
discardReadBytes 廢棄已讀位元組
mark 标記index
reset 将index重置到之前标記的位置(配合mark使用)
isReadable 如果至少有一個位元組可供讀取,則傳回 true
isWritable 如果至少有一個位元組可被寫入,則傳回 true
readableBytes 傳回可被讀取的位元組數
writableBytes 傳回可被寫入的位元組數
capacity 傳回 ByteBuf 可容納的位元組數。在此之後,它會嘗試再次擴充直到達到 maxCapacity()
maxCapacity 傳回 ByteBuf 可以容納的最大位元組數
hasArray 如果 ByteBuf 由一個位元組數組支撐,則傳回 true
array 如果 ByteBuf 由一個位元組數組支撐則傳回該數組;否則,它将抛出一個UnsupportedOperationException 異常

ByteBuf緩沖分類

1、Heap buffer(堆緩沖區):

就是将資料存在JVM堆空間中,在沒有被池化的情況可以快速配置設定和釋放。

優點:由于資料是存儲在JVM堆中,是以可以快速的建立與快速的釋放,并且它提供了直接通路内部位元組數組的方法。

缺點:每次讀寫資料時,都需要先将資料複制到直接緩沖區中再進行網路傳輸。

2、Direct buffer(直接緩沖區):

直接緩沖區,在堆外直接配置設定記憶體空間,直接緩沖區并不會占用堆的容量空間,因為它是由作業系統在本地記憶體進行的資料配置設定。

優點:在使用Socket進行資料傳遞時,性能非常好,因為資料直接位于作業系統的本地記憶體中,是以不需要從JVM将資料複制到直接緩沖區中 。

缺點:因為Direct Buffer是直接在作業系統記憶體中的,是以記憶體空間的配置設定與釋放要比堆空間更加複雜,而且速度要慢一些。

注意:

如果你的資料包含在一個在堆上的配置設定的緩沖區中,那麼事實上,在通過套接字發送他之前,jvm将會在内部把你的緩沖區複制到一個直接緩沖區中;這樣配置設定釋放就比較浪費資源;

建議:

直接緩沖區并不支援通過位元組數組的方式來通路資料。對于後端業務的消息編解碼來說,推薦使用HeapByteBuf;對于I/O通信線程在讀寫緩沖區時,推薦使用DirectByteBuf;

3、Composite Buffer 複合緩沖區:

可以擁有以上兩種的緩沖區,通過一種聚合視圖來操作底層持有的多種類型Buffer。這種緩沖,jdk nio是沒有這種特性的。

ByteBuf主要實作類

pooled:池化,重用ByteBuf對象

Direct:直接記憶體,内部通過ByteBuffer實作,典型裝飾模式

Heap:堆記憶體,内部持有byte數組

(1)UnpooledDirectByteBuf:

在堆外進行記憶體配置設定的非記憶體池ByteBuf,内部持有ByteBuffer對象,相關操作委托給ByteBuffer實作。

(2)UnpooledHeapByteBuf:

基于堆記憶體配置設定非記憶體池ByteBuf,即内部持有byte數組。

(3)UnpooledUnsafeDirectByteBuf:

和另外一個類UnpooledDirectByteBuf差不多相同,差別在于UnpooledUnsafeDirectByteBuf内部使用基于PlatformDependent相關操作實作ByteBuf,依賴平台。

(4)ReadOnlyByteBufferBuf:

隻讀ByteBuf,内部持有ByteBuffer對象,相關操作委托給ByteBuffer實作,該ByteBuf限内部使用;

(5)FixedCompositeByteBuf:

用于将多個ByteBuf組合在一起,形成一個虛拟的隻讀ByteBuf對象,不允許寫入和動态擴充。内部使用Object[]将多個ByteBuf組合在一起,一旦FixedCompositeByteBuf對象建構完成,則不會被更改。

(6)CompositeByteBuf:

用于将多個ByteBuf組合在一起,形成一個虛拟的ByteBuf對象,支援讀寫和動态擴充。内部使用List組合多個ByteBuf。一般使用使用ByteBufAllocator的compositeBuffer()方法,Unpooled的工廠方法compositeBuffer()或wrappedBuffer(ByteBuf... buffers)建立CompositeByteBuf對象。

(7)PooledByteBuf:

基于記憶體池的ByteBuf,主要為了重用ByteBuf對象,提升記憶體的使用效率;适用于高負載,高并發的應用中。主要有PooledDirectByteBuf,PooledHeapByteBuf,PooledUnsafeDirectByteBuf三個子類,PooledDirectByteBuf是在堆外進行記憶體配置設定的記憶體池ByteBuf,PooledHeapByteBuf是基于堆記憶體配置設定記憶體池ByteBuf,PooledUnsafeDirectByteBuf也是在堆外進行記憶體配置設定的記憶體池ByteBuf,差別在于PooledUnsafeDirectByteBuf内部使用基于PlatformDependent相關操作實作ByteBuf,具有平台相關性。