netty源碼解析(4.0)-21 ByteBuf的設計原理

    io.netty.buffer包中是netty ByteBuf的實現。ByteBuf是一個二進制緩衝區的抽象接口,它的功能有:html

  • 能夠隨機訪問、順序訪問。
  • 支持基本數據類型(byte, short, int, long, float, double)的序列化和反序列化。
  • 不限制底層原始的數據類型,能夠是byte[], NIO Buffer, String, IO Stream, 直接內(C語言中能夠表示爲指向一塊內置起始地址的指針void*, 內存的長度), 等等。

爲何須要ByteBuf

    緩衝區的使用範圍很是普遍:I/O操做,序列化/反序列化,編碼轉換,壓縮/解壓,加/解密等全部須要使用byte[]的場景。     有些場景須要須要可以快速地建立和銷燬緩衝區,如:高併發的服務器,處理請求、返回響應的時時候須要大量且高頻地建立,銷燬緩衝區。     有些場景不能肯定須要多大的緩衝區,如: 從數據流中分離出一條消息,消息的長度不肯定,只知道最大長度。假如消息的最大長度是64KB,而消息的平均長度只有4KB, 若是每次建立64KB的緩衝區就太浪費了。若是緩衝區可以在須要的時候自動且高效地增減容量,就完美了。     在全部的場景中都涉及到頻繁的數據copy,這要求緩衝區數據copy的性能要儘可能高。若是有可能,儘可能減小數據copy。     ByteBuf就是爲解決以上問題而設計的。java

核心概念

以下所示算法

|  discardable bytes | readable bytes |  writable bytes  |
0                readerIndex       writerIndex       capacity
  • capacity: 緩衝區的容量。
  • readerIndex: 當前讀的位置。可使用readerIndex()和readerIndex(int)方法獲取、設置readerIndex值。每次調用readXXX方法都會致使readerIndex向writerIndex移動,直到等於writerIndex爲止。
  • writerIndex: 寫的當前位置。可使用writerIndex()和writerIndex(int)方法獲取、設置writeIndex的值。每次調用writeXXX方法都會致使writeIndex向capacity移動,直到等於capacity爲止。
  • discardable bytes: 可丟棄的數據。0--readerIndex之間的數據, 長度是readerIndex - 0,調用discardReadBytes會丟棄這部分數據,把readerIndex--writerIndex之間的數據移動到ByteBuf的開始位置(0), ByteBuf會變成以下所示的樣子:
|   readable bytes  |  writable bytes  |
readerIndex(0)       writerIndex           capacity
  • readable bytes: 可讀數據。 readerIndex--writerIndex之間的數據,長度是writerInex - readerIndex。能夠調用readableBytes()方法獲得它的長度。
  • writeable bytes: 可寫的空間。長度是capacity - writerIndex。也能夠認爲它是ByteBuf的剩餘空間。

核心能力

對二進制數據的讀寫是ByteBuf的核心能力。它提供兩種讀寫方式:服務器

  • 隨機讀寫: getXXX(int), setXXX(int, ...)。不會對readerIndex和writerIndex產生影響,範圍是(0,capacity]。
  • 順序讀寫: readXXX, 增長readerIndex的值,範圍是(readerIndex, writerIndex]。 writeXXX,增長writerIndex值,範圍是(writerIndex, capacity]。

ByteBuf爲了方便使用,提供了一些基本數據類型(unsigned表示無符號類型)的讀寫支持:網絡

數據類型 長度(Byte)
byte, unsignedByte 1
short, unsignedShort 2
char 2
medium, unsignedMedium 3
int, unsignedInt 4
long 8
float 4
double 8

對這些基本數據類型的讀寫涉及到了字節須的問題,ByteBuf支持兩種字節序,使用java.nio.ByteOrder中的定義,默認的字節序是BIG_ENDIAN, 這個也是網絡字節序。併發

此外還提供了對byte[]類型及能夠當成byte[]使用的數據類型的支持, 方法名都是:getBytes,setBytes, readBytes, writeBytes。app

  • byte[]
  • ByteBuf
  • ByteBuffer
  • GatheringByteChannel
  • InputStread, OutputStream

內存管理

內存管理分爲兩個部分:內存分配,內存釋放。 ByteBufAllocator是內存分配的接口,它有兩個具體實現:UnpooledByteBufAllocator, PooledByteBufAllocator。 UnpooledByteBufAllocator是JVM內存分配接口的簡單封裝。 PooledByteBufAllocator在JVM內存分配的基礎上實現了一套獨立的內存分配算法。 內存釋放的關鍵是如何斷定對象死亡,ByteBuf繼承了ReferenceCounted接口,使用引用計數的方式斷定對象死亡。高併發

PooledByteBufAllocator中高效的內存管理算法是ByteBuf的性能基礎,理解了它的算法是理解ByteBuf的關鍵。工具

體系結構

graph TD;
B[ByteBuf]-->AB[AbstractByteBuf];
B-->SB[SwappedByteBuf];
B-->WB[WrappedByteBuf];
AB[AbstractByteBuf]-->ARCB[AbstractReferenceCountedByteBuf];
ARCB-->CB[CompositeByteBuf<br>FixedCompositeByteBuf];
ARCB-->PB[PooledByteBuf<T>];
ARCB-->UBB[UnpooledDirectByteBuf<br>UnpooledHeapByteBuf<br>UnpooledUnsafeDirectByteBuf<br>UnpooledUnsafeHeapByteBuf<br>UnpooledUnsafeNoCleanerDirectByteBuf];
ARCB-->ROBB[ReadOnlyByteBufferBuf];
PB[PooledByteBuf<T>]-->PDB[PooledDirectByteBuf];
PB-->PUDB[PooledUnsafeDirectByteBuf];
PB-->PHB[PooledHeapByteBuf];
PHB-->PUHB[PooledUnsafeHeapByteBuf];

上圖是ByteBuf體系結構中主要的類和接口。主要分爲三大類:性能

  • AbstractReferenceCountedByteBuf及其子類。這個類別是是ByteBuf中最重要的部分,它分爲4個小類別:

CompositeByteBuf, FixedCompositeByteBuf: 把不一樣的ByteBuf組合成一個ByteBuf。 PooledByteBuf:實現了自定義內存管理算法的。 UnpooledXXXX: 直接使用JVM內存管理能力。 ReadOnlyByteBufferBuf: 只讀的。

  • SwappedByteBuf: 用來轉換ByteBuf的字節序。
  • WrappedByteBuf: 用來包裝另外一個ByteBuf。

工具

有兩個工具類幫助開發者使用ByteBuf:

  • ByteBufUtil: 這個類中建立好了默認的ByteBufAllocator,能夠直接拿來用。還有一些操做ByteBuf經常使用的方法。
  • Unpooled: 這個類是針對UnpooledXXXByteBuf的工具。

用法

建立ByteBufAllocator

    使用ByteBufUtil.DEFAULT_ALLOCATOR獲得ByteBufAllocator實例。這個實例多是UnpooledByteBufAllocator,也多是PooledByteBufAllocator類型,這取決於io.netty.allocator.type屬性的設置。默認是unpooled,UnpooledByteBufAllocator類型。若是想要PooledByteBufAllocator類型,把這個屬性的值設置成pooled:     java -Dio.netty.allocator.type=pooled,或者System.setProperty("io.netty.allocator.type", "pooled")     

建立ByteBuf

    netty不建議直接建立建立ByteBuf實例,推薦使用ByteBufAllocator建立ByteBuf實例,或者使用Unpooled靜態方法。     ByteBufAllocator有7種方法用於建立ByteBuf實例:

方法名 特性
buffer 使用多是JVM堆內存或直接內存,取決於具體的實現
ioBuffer 若是能夠的話優先使用直接內存
heapBuffer 使用堆內存
directBuffer 使用直接內存
CompositeByteBuf 使用多是JVM堆內存或直接內存,取決於具體的實現
compositeHeapBuffer 使用堆內存
compositeDirectBuffer 使用堆內存

Unpooled建立ByteBuf實例的方法有2兩種:

方法名 特性
buffer 使用堆內存
directBuffer 使用直接內存

包裝成ByteBuf

Unpooled提供了一系列的wrappedBuffer方法,把一些數據類型包裝成一個ByteBuf, 這些數據類型有:

  • byte[]。
  • ByteBuffer。
  • 另外一個的ByteBuf中的可讀數據。

wrappedBuffer方法還能夠把byte[].., ByteBuffer.., ByteBuf..包裝成一個CompositeByteBuf。

數據讀寫

數據讀寫是ByteBuf的基本功能,前面已經講過,相關方法是: getXXX, readXXX, setXXX, writeXXX。

原文出處:https://www.cnblogs.com/brandonli/p/11534491.html

相關文章
相關標籤/搜索