netty源码阅读之ByteBuf之内存分配器UnpooledByteBufAllocator
我们从两个角度分析UnpooledByteBufAllocator:
1、heap内存的分配
2、direct内存的分配
由于unpooled就是自己去操作底层api去分配内存,实现起来比较简单。
一、heap内存的分配
上一篇文章其实在最后一部分我们分析过了,heap的的内存分配和读取都是在array数组上面。分配的堆内存源码就是下面UnpooledByteBufAllocator的这一段:
- @Override
- protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
- return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
- : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
- }
参考上一篇文章第三部分看可以了
二、direct内存的分配
和heap不同,direct内存分配放在buffer里面,然后unsafe的direct buffer是通过底层的unsafe类去操作的。(其实看源码到最终,direct的buffer都是通过unsafe去操作的)
从UnpooledByteBufAllocator分配direct内存的这个源码开始看起:
- @Override
- protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
- ByteBuf buf = PlatformDependent.hasUnsafe() ?
- UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
- new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
- return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
- }
我们先看unsafe吧,从UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) 这里进去:
- static UnpooledUnsafeDirectByteBuf newUnsafeDirectByteBuf(
- ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
- if (PlatformDependent.useDirectBufferNoCleaner()) {
- return new UnpooledUnsafeNoCleanerDirectByteBuf(alloc, initialCapacity, maxCapacity);
- }
- return new UnpooledUnsafeDirectByteBuf(alloc, initialCapacity, maxCapacity);
- }
不管nocleaner先,从最后UnpooledUnsafeDirectByteBuf这个函数进去:
- /**
- * Creates a new direct buffer.
- *
- * @param initialCapacity the initial capacity of the underlying direct buffer
- * @param maxCapacity the maximum capacity of the underlying direct buffer
- */
- protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
- super(maxCapacity);
- if (alloc == null) {
- throw new NullPointerException("alloc");
- }
- if (initialCapacity < 0) {
- throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
- }
- if (maxCapacity < 0) {
- throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
- }
- if (initialCapacity > maxCapacity) {
- throw new IllegalArgumentException(String.format(
- "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
- }
- this.alloc = alloc;
- setByteBuffer(allocateDirect(initialCapacity), false);
- }
最后这个allocateDirect(initialCapacity):
- /**
- * Allocate a new direct {@link ByteBuffer} with the given initialCapacity.
- */
- protected ByteBuffer allocateDirect(int initialCapacity) {
- return ByteBuffer.allocateDirect(initialCapacity);
- }
就是调用jdk底层去创建directbytebuffer。
回去setByteBuffer:
- final void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
- if (tryFree) {
- ByteBuffer oldBuffer = this.buffer;
- if (oldBuffer != null) {
- if (doNotFree) {
- doNotFree = false;
- } else {
- freeDirect(oldBuffer);
- }
- }
- }
- this.buffer = buffer;
- memoryAddress = PlatformDependent.directBufferAddress(buffer);
- tmpNioBuf = null;
- capacity = buffer.remaining();
- }
把刚刚调用allocateDirect分配的buffer赋值到this.buffer里面去。
注意memoryAddress,从这PlatformDependent.directBufferAddress(buffer);一直进去:
- static long directBufferAddress(ByteBuffer buffer) {
- return getLong(buffer, ADDRESS_FIELD_OFFSET);
- }
也就是,我们获取到内存地址,加上offset,就是我们能用的开始的地址,getLong继续就是:
- private static long getLong(Object object, long fieldOffset) {
- return UNSAFE.getLong(object, fieldOffset);
- }
调用了jdk底层unsafe加上offset为我们获取我们能用的direct地址,最终回来保存到memoryAddress里面。
回到UnpooledUnsafeDirectByteBuf的_getByte方法:
- @Override
- protected byte _getByte(int index) {
- return UnsafeByteBufUtil.getByte(addr(index));
- }
看addr(index):
- long addr(int index) {
- return memoryAddress + index;
- }
这个memoryAddress就是上面那个,也就是通过memoryAddress就能操作unsafedirect buffer内存了。
好,这就是UnpooledByteBufAllocator分配和操作direct unsafe内存的分析了
看非unsafe,一样是下面这个代码:
- @Override
- protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
- ByteBuf buf = PlatformDependent.hasUnsafe() ?
- UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
- new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
- return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
- }
从UnpooledDirectByteBuf进入:
- private void setByteBuffer(ByteBuffer buffer) {
- ByteBuffer oldBuffer = this.buffer;
- if (oldBuffer != null) {
- if (doNotFree) {
- doNotFree = false;
- } else {
- freeDirect(oldBuffer);
- }
- }
- this.buffer = buffer;
- tmpNioBuf = null;
- capacity = buffer.remaining();
- }
可以看到没有memoryAddress了,只有buffer。在UnpooledDirectByteBuf的_getByte方法里面,就是直接读取buffer里面的内容了:
- @Override
- protected byte _getByte(int index) {
- return buffer.get(index);
- }