JDK中ByteBuffer的缺點
- 只是用一個標誌位position來進行讀寫標記,讀寫操作要使用flip方法進行切換,不太友好。
- 因爲ByteBuffer中的實際存儲數據的數組是使用final修飾符修飾的,所以不可以 在原來buffer的基礎上動態擴容或者縮小。如果需要擴容,需要另外新建一個ByteBuffer,並將舊的ByteBuffer裏面的數組複製到已經擴容的ByteBuffer.
final byte[] hb;
Netty中的ByteBuf則完全對JDK中的ByteBuffer的缺點進行了改進
- 使用readerIndex和writerIndex分別維護讀操作和寫操作,實現讀寫索引分離,更加直觀。
byte[] array;
- ByteBuf使用的底層數據維護數組沒有使用final關鍵字,所以存在直接在原來ByteBuf進行擴容的可能,而這件事,Betty已經爲我們完成,封裝在它的write系列方法當中。但是它也存在着一個上限,這個上限就是Integer.MAX_VALUE.
public ByteBuf writeByte(int value) { ensureWritable0(1);//用於驗證可寫字節長度是否大於將要寫入的字節長度。 _setByte(writerIndex++, value);//寫入一個字節並且索引加一的操作。 return this; }
final void ensureWritable0(int minWritableBytes) { ensureAccessible();//驗證ByteBuf中的引用計數是否爲零,爲真則拋出異常,違背了Netty對於垃圾回收的約定 if (minWritableBytes <= writableBytes()) {//驗證可寫字節長度是否大於將要寫入的字節長度。 return;//如果是大於,則什麼都不做,直接返回 } //如果可寫字節長度小於將要寫入的最小字節長度,則需要進行擴容 if (minWritableBytes > maxCapacity - writerIndex) {//判斷如果將要到達最大的上限,則拋出異常 throw new IndexOutOfBoundsException(String.format( "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s", writerIndex, minWritableBytes, maxCapacity, this)); } // Normalize the current capacity to the power of 2.//如果可寫字節長度小於將要寫入的最小字節長度,並且沒有達到最大上限, int newCapacity = alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity);//計算擴容後capacity //擴容的當前capactiy的兩倍。 // Adjust to the new capacity. capacity(newCapacity);//重新設置capactiy.並進行數組的重新拷貝 }
public ByteBuf capacity(int newCapacity) { checkNewCapacity(newCapacity);//驗證新生成的capacity是否大於最大整數,是則拋出異常 int oldCapacity = array.length; byte[] oldArray = array; if (newCapacity > oldCapacity) { byte[] newArray = allocateArray(newCapacity);//新建一個新的數組,數組長度爲新創建capacity System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);//進行舊數組中的數組拷貝到新數組中 setArray(newArray);//將當前buffer中的array指向新數組 freeArray(oldArray);//釋放掉舊數組 } else if (newCapacity < oldCapacity) { byte[] newArray = allocateArray(newCapacity); int readerIndex = readerIndex(); if (readerIndex < newCapacity) { int writerIndex = writerIndex(); if (writerIndex > newCapacity) { writerIndex(writerIndex = newCapacity); } System.arraycopy(oldArray, readerIndex, newArray, readerIndex, writerIndex - readerIndex); } else { setIndex(newCapacity, newCapacity); } setArray(newArray); freeArray(oldArray); } return this; }