UnpooledHeapByteBuf類
UnpooledHeapByteBuf類的類圖如下所示,UnpooledHeapByteBuf繼承自AbstractReferenceCountedByteBuf類,UnpooledHeapByteBuf是一個基於JVM堆內存進行內存分配的緩衝區,是一個非池化的實現,所以在每次IO讀寫的時候都會創建一個UnpooledHeapByteBuf對象。基於堆內存的緩衝區的特點是分配和銷燬速度很快,但是在進行IO讀寫的時候多一次從內核空間向用戶空間複製的過程,故其在IO讀寫的場景下性能較低。
UnpooledHeapByteBuf對字節數據的存儲數據是大端順序
屬性
////ByteBuf的分配器,ByteBufAllocator接口的所有實現類都是現成安全的
private final ByteBufAllocator alloc;
byte[] array;//支撐數組
private ByteBuffer tmpNioBuf;//JDK Nio包中的ByteBuffer對象
構造函數
/**
* alloc:ByteBuf分配器
* initialCapacity:緩衝區的初始化容量
* maxCapacity:緩衝區的最大容量
*
*/
public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);//設置緩衝區的最大容量
if (initialCapacity > maxCapacity) {//校驗參數的合法性
throw new IllegalArgumentException(String.format(
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = checkNotNull(alloc, "alloc");//非空校驗
setArray(allocateArray(initialCapacity));//開闢數組並將其賦給緩衝區對象
setIndex(0, 0);//設置緩衝區的讀寫索引
}
/**
* alloc:ByteBuf分配器
* initialArray:緩衝區的初始化數組
* maxCapacity:緩衝區的最大容量
*
*/
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
super(maxCapacity);//設置緩衝區的最大容量
checkNotNull(alloc, "alloc");//非空校驗
checkNotNull(initialArray, "initialArray");//非空校驗
if (initialArray.length > maxCapacity) {//校驗參數的合法性
throw new IllegalArgumentException(String.format(
"initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
}
this.alloc = alloc;
setArray(initialArray);
setIndex(0, initialArray.length);//設置緩衝區的讀寫索引
}
allocateArray(int initialCapacity)和setArray(byte[] initialArray)方法如下:
protected byte[] allocateArray(int initialCapacity) {
return new byte[initialCapacity];
}
private void setArray(byte[] initialArray) {
array = initialArray;
tmpNioBuf = null;
}
設置緩衝區的容量
UnpooledHeapByteBuf#capacity(int newCapacity)方法的大致邏輯如下:
1、如果newCapacity == oldCapacity則不用做任何操作,直接返回
2、如果newCapacity > oldCapacity,表示需要做擴容操作,執行擴容操作時,讀寫索引索引不需要被重置,只需要執行數組拷貝即可
3、如果newCapacity > oldCapacity,表示需要做縮容操作,此時需要再做如下判斷
3.1如果newCapacity >= writerIndex,則不需要修改讀寫索引,直接執行數組複製即可
如下圖所示:無需修改讀寫索引,直接進行數組拷貝操作即可
3.2 如果newCapacity < writerIndex,將寫索引設置爲newCapacity,讀索引爲newCapacity和readerIndex二者的最小值
如下圖所示,newCapacity < writerIndex,此時需要重新設置讀寫指針
執行讀寫指針重置並拷貝數組後得到的新的數組如下圖橙色部分所示:
@Override
public ByteBuf capacity(int newCapacity) {
checkNewCapacity(newCapacity);
byte[] oldArray = array;
int oldCapacity = oldArray.length;
if (newCapacity == oldCapacity) {
return this;
}
int bytesToCopy;
if (newCapacity > oldCapacity) {
bytesToCopy = oldCapacity;
} else {
trimIndicesToCapacity(newCapacity);
bytesToCopy = newCapacity;
}
byte[] newArray = allocateArray(newCapacity);
System.arraycopy(oldArray, 0, newArray, 0, bytesToCopy);//native方法
setArray(newArray);
freeArray(oldArray);
return this;
}
字節數組的複製
UnpooledHeapByteBuf類對於字節數組的複製的實現是直接調本地方法System.arraycopy完成的
@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;
}
將字節數組轉換爲jdk nio包下的ByteBuffer
Netty的實現也是調用ByteBuffer的wrap方法完成的,與ByteBuffer不同的是netty又調用的slice()方法,ByteBuffer#slice()方法的作用是創建一個源緩衝區的淺拷貝,從源緩衝區的position開始。
@Override
public ByteBuffer nioBuffer(int index, int length) {
ensureAccessible();
return ByteBuffer.wrap(array, index, length).slice();
}
釋放緩衝區的實現
@Override
protected void deallocate() {
freeArray(array);
array = EmptyArrays.EMPTY_BYTES;
}