UnpooledHeadByteBuf源码分析
来源:互联网 发布:高级软件开发工程师 编辑:程序博客网 时间:2024/05/22 23:29
1.简单介绍
1.UnpooledHeadByteBuf简介
UploadedHeadByteBuf是基于堆内存进行内存分配的字节缓存区,他没有基于对象池的技术实现,意味着每次io的读写都会创建一个新的UnpooledHeadByteBuf,频繁进行大块内存的分配和回收对性能会造成一定的影响,但是相比于堆外内存的申请和释放,他的成本低一点。
相比于PooledHeadbyteBuf,
UnpooledHeadByteBuf的实现原理更加简单,也不容易出现内存管理方面的问题,因此在满足性能的情况下,推荐使用UnpooledHeadByteBuf。
2.1成员变量
private final ByteBufAllocator alloc; private byte[] array; private ByteBuffer tmpNioBuf;
ByteBufAllocate用于UnpooledHeapByteBuf的内存分配
byte数组作为缓存区
temNioBuf用于实现ByteBuf到ByteBuffer的转换
2.2构造方法
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) { this(alloc, initialArray, 0, initialArray.length, maxCapacity); } private UnpooledHeapByteBuf( ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) { super(maxCapacity); if (alloc == null) { throw new NullPointerException("alloc"); } if (initialArray == null) { throw new NullPointerException("initialArray"); } if (initialArray.length > maxCapacity) { throw new IllegalArgumentException(String.format( "initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity)); } this.alloc = alloc; setArray(initialArray); setIndex(readerIndex, writerIndex); }
没什么特殊的地方,很容易理解
3.动态扩展缓存。
在前面介绍AbstractByteBuf的时候,有一个setBytes()写操作,我们还提到写的方法与读的方法的不一样的地方在于它能够动态扩展,setBytes()函数中,有一个ensureWritable(int minWritableBytes)
函数专门用来检查length:
1.如果长度参数小于零,抛出错误。
2.如果长度小于可读长度(capacity() - writerIndex),老铁没毛病,过去吧。
3.如果长度大于最大可读长度(maxCapacity - writerIndex),对不起,抛出错误。
4.当长度大于可读长度小于最大可读长度,这时候需要动态扩展了
int newCapacity = alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity); capacity(newCapacity);
计算最新的容量有ByteBufAllowcator帮我们完成,但是capacity(newCapacity)在AbstractByteBuf中并没有实现,原因是动态扩展要根据ByteBuf是内存的还是堆的来决定。
说了这么多废话,其实就是UnpooledHeadByteBuf这个类和他的兄弟UnpooledDirectByteBuf类都要实现Capacity这个方法,实现的方式不一样而已。
来看他的代码
如果新的容量小于零或者大于最大容量,抛出错误。
如果新的容量大于旧的容量,那么直接将新建一个缓存区,将旧的复制到新的中
如果新的容量小于旧的容量,就要进行缩小容量,就是新建一个新的缓存区,判断readIndex和新的容量,如果readIndex大于新的容量,那么直接将readIndex和WriteIndex设置为新的缓存区的readIndex和WriteIndex;
如果readIndex小于新的容量,就要判断writeIndex和新的容量,如果writeIndex大于新的容量,那么直接吧writeIndex设置为新的缓存区的writeIndex,然后进行缓存区的复制。
System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
4.读操作方法
@Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { checkDstIndex(index, length, dstIndex, dst.capacity()); if (dst.hasMemoryAddress()) { PlatformDependent.copyMemory(array, index, dst.memoryAddress() + dstIndex, length); } else if (dst.hasArray()) { getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length); } else { dst.setBytes(dstIndex, array, index, length); } return this; } @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { checkDstIndex(index, length, dstIndex, dst.length); System.arraycopy(array, index, dst, dstIndex, length); return this; }
checkDstIndex(index, length, dstIndex, dst.capacity());
检查函数就不必多说了,比较简单。
首先检查目标数组时候有低位数的内存地址,如果有,直接
PlatformDependent.copyMemory(array, index, dst.memoryAddress() + dstIndex, length);
然后检查目标有没有array缓存区,(实际上是检查是不是Heap中的吧),如果是就
getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
这个函数实际上就是System.arraycopy(array, index, dst, dstIndex, length)
方法,实际上也验证了我的判断:和上面的动态扩展一样,如果是同样来自Heap中的ByteBuf的复制,用这个arraycopy方法就OK啦!
5.写操作
@Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { checkSrcIndex(index, length, srcIndex, src.capacity()); if (src.hasMemoryAddress()) { PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, array, index, length); } else if (src.hasArray()) { setBytes(index, src.array(), src.arrayOffset() + srcIndex, length); } else { src.getBytes(srcIndex, array, index, length); } return this; } @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; }
嘿嘿,和读操作一模一样。‘
6.转换成JDK ByteBuffer
public ByteBuffer nioBuffer(int index, int length) { ensureAccessible(); return ByteBuffer.wrap(array, index, length).slice(); }
一个简单的不能再简单的函数:直接调用ByteBuffer的wrap方法搞定
public static ByteBuffer wrap(byte[] array, int offset, int length) { try { return new HeapByteBuffer(array, offset, length); } catch (IllegalArgumentException x) { throw new IndexOutOfBoundsException(); } }
- UnpooledHeadByteBuf源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析:SparseArray分析
- 源码- Spark Broadcast源码分析
- Android源码/框架源码分析
- 【Android应用源码分析】HandlerThread 源码分析
- 【Android应用源码分析】IntentService 源码分析
- java源码分析01-Object源码分析
- VC++源码分析 - 中国象棋源码分析
- [Java源码分析]ArrayList源码分析
- [java源码分析]LinkedList源码分析
- 2
- 世先有良医然后才有良药
- shell_编程2(语法)
- 每天学一点Swift----面向对象上(三)
- compass 中的 页脚固定 sticky-footer
- UnpooledHeadByteBuf源码分析
- 风格转换简介
- 计算机网络之TCP实验(wireshark版)
- Linux内建命令
- 侯捷-《STL源码剖析》的一些可能的错误
- Webpack基础之输出
- C++格式化输出,C++输出格式控制
- codevs 1643 线段覆盖 3(贪心+快排)
- 探究线性表与链表