Netty源碼分析第5章(ByteBuf)---->第2節: ByteBuf的分類

 

Netty源碼分析第五章: ByteBufhtml

 

第二節: ByteBuf的分類api

 

上一小節簡單介紹了AbstractByteBuf這個抽象類, 這一小節對其子類的分類作一個簡單的介紹數組

ByteBuf根據不一樣的分類方式, 會有不一樣的分類結果安全

咱們首先看第一種分類方式:jvm

1.Pooled和Unpooled:函數

pooled是從一塊內存裏去取一段連續內存封裝成byteBuf源碼分析

具體標誌是類名以Pooled開頭的ByteBuf, 一般就是Pooled類型的ByteBuf, 好比: PooledDirectByteBuf或者pooledHeapByteBufthis

有關如何分配一塊連續的內存, 咱們以後的章節會講到spa

 

Unpooled是分配的時候直接調用系統api進行實現, 具體標誌是以Unpooled開頭的ByteBuf, 好比UnpooledDirectByteBuf, UnpooledHeapByteBuf指針

再看第二種分類方式:

2.基於直接內存的ByteBuf和基於堆內存的ByteBuf

基於直接內存的ByteBuf, 具體標誌是類名中包含單詞Direct的ByteBuf, 好比UnpooledDirectByteBuf, PooledDirectByteBuf等

基於堆內存的ByteBuf, 具體標誌是類名中包含單詞heap的ByteBuf, 好比UnpooledHeapByteBuf, PooledHeapByteBuf

 

結合以上兩種方式, 這裏經過其建立的方式去簡單對其分類作個解析

這裏第一種分類的Pooled, 也就是分配一塊連續內存建立byteBuf, 這一小節先不進行舉例, 會在以後的小節講到

這裏主要就看Unpooled, 也就是調用系統api的方式建立byteBuf, 在直接內存和堆內存中有什麼區別

這裏以UnpooledDirectByteBuf和UnpooledHeapByteBuf這兩種爲例, 簡單介紹其建立方式:

首先看UnpooledHeapByteBuf的byetBuf, 這是基於內存建立ByteBuf, 而且是直接調用系統api

咱們看UnpooledHeapByteBuf的byetBuf的構造方法:

 protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) { this(alloc, new byte[initialCapacity], 0, 0, maxCapacity); }

這裏調用了自身的構造方法, 參數中建立了新的字節數組, 初始長度爲初始化的內存大小, 讀寫指針初始位置都是0, 並傳入了最大內存大小

從這裏看出, 有關堆內存的Unpooled類型的分配, 是經過字節數組進行實現的

再往下跟:

protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) { this(alloc, initialArray, 0, initialArray.length, maxCapacity); }

繼續跟:

private UnpooledHeapByteBuf( ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) { super(maxCapacity); //忽略驗證代碼
    this.alloc = alloc; setArray(initialArray); setIndex(readerIndex, writerIndex); }

跟到setAarry方法中:

private void setArray(byte[] initialArray) { array = initialArray; tmpNioBuf = null; }

將新建立的數組賦值爲自身的array屬性

回到構造函數中, 跟進setIndex方法:

public ByteBuf setIndex(int readerIndex, int writerIndex) { //忽略驗證代碼
 setIndex0(readerIndex, writerIndex); return this; }

這裏其實是調用了AbstractByteBuf的setIndex方法

咱們跟進setIndex0方法中:

final void setIndex0(int readerIndex, int writerIndex) { this.readerIndex = readerIndex; this.writerIndex = writerIndex; }

這裏設置了讀寫指針, 根據以前的調用鏈咱們知道, 這裏將讀寫指針位置都設置爲了0

介紹完UnpooledHeapByteBuf的初始化, 咱們繼續看UnpooledDirectByteBuf這個類的構造, 顧明思議, 是基於堆外內存, 而且一樣也是調用系統api的方式進行實現的

咱們看其構造方法:

protected UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) { super(maxCapacity); //忽略驗證代碼
    this.alloc = alloc; setByteBuffer(ByteBuffer.allocateDirect(initialCapacity)); }

咱們關注下setByteBuffer中的參數ByteBuffer.allocateDirect(initialCapacity)

咱們在這裏看到, 這裏經過jdk的ByteBuffer直接調用靜態方法allocateDirect分配了一個基於直接內存的ByteBuffer, 並設置了初始內存

再跟到setByteBuffer方法中:

private void setByteBuffer(ByteBuffer buffer) { ByteBuffer oldBuffer = this.buffer; if (oldBuffer != null) { //代碼忽略
 } this.buffer = buffer; tmpNioBuf = null; capacity = buffer.remaining(); }

咱們看到在這裏將分配的ByteBuf設置到當前類的成員變量中

 

以上兩種實例, 咱們會對上面所講到的兩種分類有個初步的瞭解

這裏要注意一下, 基於堆內存建立ByteBuf, 能夠不用考慮對象回收, 由於虛擬機會進行垃圾回收, 可是堆外內存在虛擬機的垃圾回收機制的做用域以外, 因此這裏要考慮手動回收對象

最後, 咱們看第三種分類方式:

3.safe和unsafe

首先從名字上看, safe表明安全的, unsafe表明不安全的

這個安全與不安全的定義是什麼呢

其實在咱們jdk裏面有unsafe對象, 能夠經過unsafe對象直接拿到內存地址, 基於內存地址能夠進行讀寫操做

若是是Usafe類型的byteBuf, 則能夠直接拿到byteBuf在jvm中的具體內存, 能夠經過調用jdk的Usafe對象進行讀寫, 因此這裏表明不安全

而非Usafe不能拿到jvm的具體內存, 因此這裏表明安全

具體標誌是若是類名中包含unsafe這個單詞的ByteBuf, 能夠認爲是一個unsafe類型的ByteBuf, 好比PooledUnsafeHeapByteBuf或者PooledUnsafeDirectByteBuf

以PooledUnsafeHeapByteBuf的_getByte方法爲例:

protected byte _getByte(int index) { return UnsafeByteBufUtil.getByte(memory, idx(index)); }

這裏memory表明byebuffer底層分配內存的首地址, idx(index)表明當前指針index距內存memory的偏移地址, UnsafeByteBufUtil的getByte方法, 就能夠直接經過這兩個信息經過jdk底層的unsafe對象拿到jdk底層的值

有關AbstractByteBuf的主要實現類和繼承關係, 以下圖所示:

5-2-1

 

上一節: AbstractByteBuf

下一節: 緩衝區分配器

相關文章
相關標籤/搜索