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; }