標籤:啟動 length test 緩衝 mat img ret atom 控制
每種ByteBuf都有相應的分配器ByteBufAllocator,類似原廠模式。我們先學習UnpooledHeapByteBuf與其對應的分配器UnpooledByteBufAllocator
如何知道alloc分配器那是個?
可以從官方下載的TimeServer 例子來學習,本項目已有源碼可在 TestChannelHandler.class裡斷點追蹤
從圖可以看出netty 4.1.8預設的ByteBufAllocator是PooledByteBufAllocator,可以參過啟動參數-Dio.netty.allocator.type unpooled/pooled 設定
細心的讀者可以看出分配ByteBuf只有pool跟unpool,但ByteBuf有很多類型,可能出於使用方面考慮,有時不一定設計太死板,太規範反而使學習成本很大
public final class ByteBufUtil { static final ByteBufAllocator DEFAULT_ALLOCATOR; static { String allocType = SystemPropertyUtil.get( "io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled"); allocType = allocType.toLowerCase(Locale.US).trim(); ByteBufAllocator alloc; if ("unpooled".equals(allocType)) { alloc = UnpooledByteBufAllocator.DEFAULT; } else if ("pooled".equals(allocType)) { alloc = PooledByteBufAllocator.DEFAULT; } else { alloc = PooledByteBufAllocator.DEFAULT; } DEFAULT_ALLOCATOR = alloc; }}
AbstractReferenceCountedByteBuf是統計引用總數處理,用到Atomic*技術。
refCnt是從1開始,每引用一次加1,釋放引用減1,當refCnt變成1時執行deallocate由子類實現
public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf { private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt"); private volatile int refCnt = 1; @Override public ByteBuf retain() { return retain0(1); } private ByteBuf retain0(int increment) { for (;;) { int refCnt = this.refCnt; final int nextCnt = refCnt + increment; if (nextCnt <= increment) { throw new IllegalReferenceCountException(refCnt, increment); } if (refCntUpdater.compareAndSet(this, refCnt, nextCnt)) { break; } } return this; } @Override public boolean release() { return release0(1); } private boolean release0(int decrement) { for (;;) { int refCnt = this.refCnt; if (refCnt < decrement) { throw new IllegalReferenceCountException(refCnt, -decrement); } if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) { if (refCnt == decrement) { deallocate(); return true; } return false; } } } protected abstract void deallocate();}
對於ByteBuf I/O 操作經常用的是 writeByte(byte[] bytes) readByte(byte[] bytes) 兩種
由於ByteBuf支援多種bytes對象,如 OutputStream、GatheringByteChannel、ByteBuffer、ByteBuf等,
我們只拿兩三種常用的API來做分析,其它邏輯大同小異
如果讀者有印象的話,通常底層只負責流程式控制制,實現交給應用程式層/子類處理,AbstractByteBuf.class writeByte/readByte 也是這種處理方式
public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { //分配器 private final ByteBufAllocator alloc; //資料 byte[] array; //臨時ByteBuffer,用於內部緩衝 private ByteBuffer tmpNioBuf; private UnpooledHeapByteBuf( ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) { //省去部分代碼同邊界處理 super(maxCapacity); this.alloc = alloc; array = initialArray; this.readerIndex = readerIndex; this.writerIndex = writerIndex; } //擷取ByteBuffer容量 @Override public int capacity() { ensureAccessible(); return array.length; } @Override public boolean hasArray() { return true; } //擷取未經處理資料 @Override public byte[] array() { ensureAccessible(); return array; } //擴容/縮容 @Override public ByteBuf capacity(int newCapacity) { ensureAccessible(); //newCapacity參數邊界判斷 if (newCapacity < 0 || newCapacity > maxCapacity()) { throw new IllegalArgumentException("newCapacity: " + newCapacity); } int oldCapacity = array.length; //擴容處理,直接cp到新的array if (newCapacity > oldCapacity) { byte[] newArray = new byte[newCapacity]; System.arraycopy(array, 0, newArray, 0, array.length); setArray(newArray); } else if (newCapacity < oldCapacity) { //減容處理 //這裡有兩種處理情況 //1.readerIndex > newCapacity 說明還有資料未處理直接將 readerIndex,writerIndex相等 newCapacity //2.否則 writerIndex =Math.min(writerIndex,newCapacity),取最少值,然後直接複製資料 //可以看出netty處理超出readerIndex、writerIndex 限界直接丟棄資料。。。。。。 byte[] newArray = new byte[newCapacity]; int readerIndex = readerIndex(); if (readerIndex < newCapacity) { int writerIndex = writerIndex(); if (writerIndex > newCapacity) { writerIndex = newCapacity this.writerIndex = writerIndex; } System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex); //System.arraycopy(複製來源數組, 來源組起始座標, 目標數組, 目標數組起始座標, 複製資料長度); } else { this.readerIndex = newCapacity; this.writerIndex = newCapacity; } setArray(newArray); } return this; }}
未完侍。。。。。
[編織訊息架構][netty源碼分析]11 UnpooledHeapByteBuf 與 ByteBufAllocator