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