UnpooledHeapByteBuf源码解析

UnpooledHeapByteBuf源码解析教程

UnpooledHeapByteBuf 是基于堆内存进行内存分配的字节缓冲区,它没有基于对象池技术实现。在每次 I/O 的读写都会创建一个新的 UnpooledHeapByteBuf,频繁进行大块内存的分配和回收对性能会造成一定影响,但是相比于堆外内存的申请和释放,它的成本会比较低一点。

成员变量

该类里面的成员变量如下:

16 UnpooledHeapByte 变量定义.png

它里面定义了一个 ByteBufAllocator 类型的 alloc,用来对 UnpooledHeapByteBuf 的内存分配。定义了一个 byte[] 数组的 array 作为一个缓冲区。tmpNioBuf 的类型是 ByteBuffer 的,它是用来实现 Netty 的 ByteBuf 到 JDK NIO 的 ByteBuffer 的转换。

动态扩展缓冲区

从前面的章节中,我们了解到 Netty 的 ByteBuf 和 JDK NIO 的 ByteBuffer 的重要区别是 JDK 的 ByteBuffer 不能自动扩容,而在 Netty 中它可以自动扩容。UnpooledHeapByteBuf 的扩容方法为 capacity,具体的源码如下:

public ByteBuf capacity(int newCapacity) { checkNewCapacity(newCapacity); int oldCapacity = array.length; byte[] oldArray = array; if (newCapacity > oldCapacity) { byte[] newArray = allocateArray(newCapacity); System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); setArray(newArray); 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; }

具体的逻辑分析如下

17 UnpooledHeapByteBuf 扩容代码流程图.png

字节数组复制

字节数组复制的方法是 setBytes。这边我们具体了解一下 public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) 方法。它的源代码如下:

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

它会先进行合法性校验,校验 index 和 length 的值,如果它们小于 0,就会抛出异常。然后对两个值的和与它的缓冲区容量比较,如果大于缓冲区容量,也会抛出异常。如果校验通过就会调用系统的 System.arraycopy 方法对数组进行复制。

ByteBuf 中以 get 和 set 开头的读写缓冲区的方法并不会修改读写索引。

转换成JDK的ByteBuffer

从前面的章节中,我们了解到 ByteBuf 基于 byte 数组实现,NIO 的 ByteBuffer 提供了 wrap 方法,可以将 byte 数组转换成 Bytebuffer 对象。它的源代码如下:

UnpooledHeapByteBuf 类

@Override public ByteBuffer nioBuffer(int index, int length) { ensureAccessible(); return ByteBuffer.wrap(array, index, length).slice(); }

ByteBuffer类

public static ByteBuffer wrap(byte[] array, int offset, int length) { try { return new HeapByteBuffer(array, offset, length); } catch (IllegalArgumentException x) { throw new IndexOutOfBoundsException(); } }

它调用了 ByteBuffer 的 slice 方法,用来创建一个新的字节数组缓冲区,和原来的缓冲区是隔离开的。

UnpooledHeapByteBuf总结

本章我们分析了 netty 的 UnpooledHeapByteBuf 源码,它是基于堆内存进行操作的。分析了它的成员变量,扩容复制等机制,对 Netty 的 ByteBuf 的了解更进一步。