本文分享內容如下
- AbstractByteBuf分析
- readXXX系列方法
- 讀寫方法分析
- ensureWritable分析
- capacity分析
- setBytes(int, byte[], int, int) 分析
- AbstractReferenceCountedByteBuf分析
- ByteBuffer-put系列方法分析
- UnpooledHeapByteBuf分析
- Head,Direct,UnsafeDirect 三種類型ByteBuf區別分析
- 內存池分配器分析
ByteBuf概覽
主要類繼承圖如下
下面逐個進行分析
AbstractByteBuf分析
readXXX系列方法
//int 相當於4個byte大小,讀取4個byte位,拼接成int
public int readInt() {
checkReadableBytes(4);
int v = _getInt(readerIndex);//將4位byte按照高低拼接。
readerIndex += 4;
return v;
}
同理 readShort 2個byte,readLong 8個byte。
讀寫方法分析
AbstractByteBuf中讀寫方法比較多,下面讀寫各分析一個典型的方法
//將當前的ByteBuf中從dstIndex開始長度爲length的數據寫入到sdt中,讀取成功readerIndex增加length
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
checkReadableBytes(length);//簡單的校驗
getBytes(readerIndex, dst, dstIndex, length);//拷貝到src中
readerIndex += length;
return this;
}
將src中從srcIndex開始長度爲length的數據寫入到當前Buf中,寫入成功writerIndex增加length
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
ensureWritable(length);
setBytes(writerIndex, src, srcIndex, length);//與readBytes中使用同一方法
writerIndex += length;
return this;
}
ensureWritable(length);在讀寫中都用到了,下面詳細分析一下。
ensureWritable分析
public ByteBuf ensureWritable(int minWritableBytes) {
//各種check
// Normalize the current capacity to the power of 2.
//計算新容量
int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);
// Adjust to the new capacity.
capacity(newCapacity);//擴容或縮容量
return this;
}
private int calculateNewCapacity(int minNewCapacity) {
final int maxCapacity = this.maxCapacity;
final int threshold = 1048576 * 4; // 4 MiB page //大容量時 計劃每次增長4MB
if (minNewCapacity == threshold) {
return threshold;
}
// If over threshold, do not double but just increase by threshold.
if (minNewCapacity > threshold) {// 新容量較大,進行大容量擴容
int newCapacity = minNewCapacity / threshold * threshold; //獲取threshold整數倍的容量值
if (newCapacity > maxCapacity - threshold) {//應該增長threshold,但是最大容量不允許,新容量爲最大容量
newCapacity = maxCapacity;
} else {//增長threshold
newCapacity += threshold;
}
return newCapacity;
}
//容較小,進行小容量擴容
int newCapacity = 64;
//取64*2N次冪 大於minNewCapacity 的最小值
// 如 minNewCapacity=255 newCapacity 最後等於 512
while (newCapacity < minNewCapacity) {
newCapacity <<= 1;
}
//防止newCapacity超出maxCapacity,默認 maxCapacity是Integer.MAX, 如果newCapacity超出maxCapacity,newCapacity至少是maxCapacity的1/2,應該在大容量擴容就被處理掉了,此時下面這個取最小值沒有用。
return Math.min(newCapacity, maxCapacity);
}
capacity分析
capacity有不同的實現,下面舉例分析,其他實現邏輯上相同,細節有按照其特性實現。
io.netty.buffer.UnpooledDirectByteBuf-capacity分析
public ByteBuf capacity(int newCapacity) {
ensureAccessible();
if (newCapacity < 0 || newCapacity > maxCapacity()) {
throw new IllegalArgumentException("newCapacity: " + newCapacity);
}
int readerIndex = readerIndex();
int writerIndex = writerIndex();
int oldCapacity = capacity;
if (newCapacity > oldCapacity) {//擴容
ByteBuffer oldBuffer = buffer;
ByteBuffer newBuffer = allocateDirect(newCapacity);
oldBuffer.position(0).limit(oldBuffer.capacity());
newBuffer.position(0).limit(oldBuffer.capacity());
newBuffer.put(oldBuffer);//put的邏輯是將 src limit減去position 即src.remaining() 長度的byte拷貝到 newBuffer中,從position 開始。
//這裏是將oldBuffer中的byte拷貝到newBuffer中去,擴容的同時也複製了數據
newBuffer.clear();
setByteBuffer(newBuffer);
} else if (newCapacity < oldCapacity) {//縮容量
ByteBuffer oldBuffer = buffer;
ByteBuffer newBuffer = allocateDirect(newCapacity);
if (readerIndex < newCapacity) {//當前寫入索引小於新容量
if (writerIndex > newCapacity) { //readerIndex < newCapacity<writerIndex 只能截取 readerIndex ~newCapacity 的有效數據
writerIndex(writerIndex = newCapacity);
}
//當writerIndex < newCapacity==true,即readerIndex <writerIndex <newCapacity,不需要處理writerIndex
//拷貝oldBuffer有效數據到newBuffer
oldBuffer.position(readerIndex).limit(writerIndex);
newBuffer.position(readerIndex).limit(writerIndex);
newBuffer.put(oldBuffer);
newBuffer.clear();
} else {//這塊不理解,感覺有問題
setIndex(newCapacity, newCapacity);
}
setByteBuffer(newBuffer);//設置核心依賴的ByteBuffer
}
return this;
}
setBytes(int, byte[], int, int) 分析
setBytes與capacity情況類似,下面舉例分析。
UnpooledHeapByteBuf.setBytes(int, byte[], int, int) 分析
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);//檢查 防止數組越界
System.arraycopy(src, srcIndex, array, index, length);//byte copy
return this;
}
使用arraycopy完成byte拷貝
到此 AbstractByteBuf的讀寫典型方法就分析完了
操作索引方法
這部分方法比較簡單,不詳細分析
public ByteBuf readerIndex(int readerIndex):設置讀索引
public ByteBuf writerIndex(int writerIndex):設置寫索引
還有mark,reset readerIndex和writerIndex方法。
@Override
public int maxWritableBytes() {
return maxCapacity() - writerIndex;
}
@Override
public ByteBuf markReaderIndex() {
markedReaderIndex = readerIndex;
return this;
}
@Override
public ByteBuf resetReaderIndex() {
readerIndex(markedReaderIndex);
return this;
}
@Override
public ByteBuf markWriterIndex() {
markedWriterIndex = writerIndex;
return this;
}
@Override
public ByteBuf resetWriterIndex() {
writerIndex = markedWriterIndex;
return this;
}
重用緩存方法分析
public ByteBuf discardReadBytes() {
ensureAccessible();
if (readerIndex == 0) {
return this;
}
if (readerIndex != writerIndex) {//數據被讀取部分
setBytes(0, this, readerIndex, writerIndex - readerIndex);//未讀數據前移
writerIndex -= readerIndex;
adjustMarkers(readerIndex);//調整mark值
readerIndex = 0;
} else {//數據全部讀取
adjustMarkers(readerIndex);
writerIndex = readerIndex = 0;
}
return this;
}
//跳過length個byte數據, readerIndex+=length
public ByteBuf skipBytes(int length) {
checkReadableBytes(length);
int newReaderIndex = readerIndex + length;
if (newReaderIndex > writerIndex) {//新的readerIndex不能超過writerIndex
throw new IndexOutOfBoundsException(String.format(
"length: %d (expected: readerIndex(%d) + length <= writerIndex(%d))",
length, readerIndex, writerIndex));
}
readerIndex = newReaderIndex;
return this;
}
AbstractReferenceCountedByteBuf分析
都是維護引用值的方法
引用值加1
public ByteBuf retain() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, 1);
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalReferenceCountException(Integer.MAX_VALUE, 1);
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
break;
}
}
return this;
}
引用值加increment
public ByteBuf retain(int increment) {
//...
}
引用值減1
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, -1);
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
if (refCnt == 1) {
deallocate();
return true;
}
return false;
}
}
}
引用值減decrement
public final boolean release(int decrement) {
//...
}
小結:AbstractReferenceCountedByteBuf中實現維護引用值得的多個方法
ByteBuffer-put系列方法分析
ByteBuf最終的實現類大量用到了ByteBuffer-put系列方法,瞭解其用法是很重要的。
注意:除了指定了寫入位置的方法,下面分析的方法都從當前ByteBuffe的position 開始,。
將 src的 limit減去position 即src.remaining() 長度的byte拷貝到 當前ByteBuffer 中。
public ByteBuffer put(ByteBuffer src);
將src從offset開始length長度的byte拷貝到 當前ByteBuffer 中。
public ByteBuffer put(byte[] src, int offset, int length)
寫入一個byte b值到 當前ByteBuffer 中。
public ByteBuffer put(byte b);
寫入一個char b值到 當前ByteBuffer 中,char 類型2個byte大小,value值被拆成高低2個byte。
public ByteBuffer putChar(char value);
由於int 4個byte,short 2個byte,long 8個byte, float4個byte,double,long 8個byte
還有public ByteBuffer putXXX(char value);方法與putChar方法同理
在指定的位置寫入value值
public abstract ByteBuffer putChar(int index, char value);
與putChar(char value)相同,還有 puttXXX(int index, char value);
UnpooledHeapByteBuf分析
getBytes系列方法
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
ensureAccessible();
dst.put(array, index, Math.min(capacity() - index, dst.remaining()));
return this;
}
getBytes是將數據寫入指定目標,這個指定目標可以是 ByteBuf,byte[],ByteBuffer,OutputStream,GatheringByteChannel類型
UnpooledHeapByteBuf中只有一個readBytes方法,用於從當前buf中讀出指定長度寫到channel中去。
public int readBytes(GatheringByteChannel out, int length) throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length, true);
readerIndex += readBytes;
return readBytes;
}
setBytes系列方法
與getBytes相對應的是setBytes系列方法,是將指定目標數據寫入寫入當前buf,這個指定目標可以是 ByteBuf,byte[],ByteBuffer,OutputStream,GatheringByteChannel類型
獲取基本類型的拼接方法 如
protected int _getInt(int index) {
return (array[index] & 0xff) << 24 |
(array[index + 1] & 0xff) << 16 |
(array[index + 2] & 0xff) << 8 |
array[index + 3] & 0xff;
}
截取一段創建新的ByteBuf
public ByteBuf copy(int index, int length) {
checkIndex(index, length);
byte[] copiedArray = new byte[length];
System.arraycopy(array, index, copiedArray, 0, length);
return new UnpooledHeapByteBuf(alloc(), copiedArray, maxCapacity());
}
//將ByteBuf 轉換成ByteBuffer
private ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.tmpNioBuf;
if (tmpNioBuf == null) {//use array new HeapByteBuffer
this.tmpNioBuf = tmpNioBuf = ByteBuffer.wrap(array);
}
return tmpNioBuf;
}
@Override
public ByteBuf copy(int index, int length) {
ensureAccessible();
ByteBuffer src;
try {
src = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
}
return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
}
ByteBuf pool, 創建工具類,輔助工具類。
Head,Direct,UnsafeDirect 三種類型ByteBuf區別分析
UnpooledHeadByteBuf
private UnpooledHeapByteBuf(
ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
super(maxCapacity);
//。。。
this.alloc = alloc;
setArray(initialArray);//數組
setIndex(readerIndex, writerIndex);
}
//內部數據使用byte[]維護
存數據典型方法:setBytes(int, byte[], int, int)
數組實現
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);
System.arraycopy(src, srcIndex, array, index, length);
return this;
}
UnpooledDirectByteBuf
構造方法
protected UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
//...
this.alloc = alloc;
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));//new DirectByteBuffer(capacity)
}
//與UnpooledUnsafeDirectByteBuf相同, 內部數據使用DirectByteBuffer維護。
存數據典型方法:setBytes(int, byte[], int, int)
NIO DirectByteBuffer 實現
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index).limit(index + length);
tmpBuf.put(src, srcIndex, length);
return this;
}
UnpooledUnsafeDirectByteBuf
protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
//...
this.alloc = alloc;
setByteBuffer(allocateDirect(initialCapacity));//new DirectByteBuffer(capacity)
}
//內部數據使用DirectByteBuffer維護。
存數據典型方法:setBytes(int, byte[], int, int)
使用Unsafe直接操作內存實現。
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkIndex(index, length);
if (length != 0) {
PlatformDependent.copyMemory(src, srcIndex, addr(index), length);
}
return this;
}
static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
}
內存池分配器分析
常用的分配方法: AbstractByteBufAllocator.directBuffer(int, int)
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
validate(initialCapacity, maxCapacity);
return newDirectBuffer(initialCapacity, maxCapacity);
}
UnpooledByteBufAllocator的實現
//直接調用構造方法
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
ByteBuf buf;
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
return toLeakAwareBuffer(buf);
}
PooledByteBufAllocator的實現
使用內存池
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<ByteBuffer> directArena = cache.directArena;
ByteBuf buf;
if (directArena != null) {//通常會執行這裏
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {//執行 UnpooledByteBufAllocator的 newDirectBuffer邏輯
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
}
return toLeakAwareBuffer(buf);
}