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去操作的,也就是jdk底层的allocateDirect最终还是调用到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,就是我们能用的开始的地址(通过buffer算出内存地址保存到memoryAddress,这样就可以知道buffer在内存里面的地址是多少了),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内存了(通过memoryAddress+index当做内存地址)。 

好,这就是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);
    }

 

再总结一下,

UnpooledHeapByteBuf和UnpooledUnsafeHeapByteBuf存储的时候,都是通过一个array。但是_getByte(array,index)的时候,UnpooledHeapByteBuf底层是直接操作array;而 UnpooledUnsafeHeapByteBuf是通过UNSAFE操作这个数组。

UnpooledDirectByteBuf和UnpooledUnsafeDirectByteBuf存储的时候,都通过了一个buffer存储(而且UnpooledUnsafeDirectByteBuf还会计算这个buffer在内存的地址memoryAddress,以后通过操作这个memoryAddress+index操作buffer)。_getByte(index)的时候UnpooledDirectByteBuf通过操作这个buffer操作数据;而UnpooledUnsafeDirectByteBuf通过操作unsafe操作index'(这个index'是memoryAddress+index得来的)来操作数据。(但是其实操作jdk底层buffer的时候都是通过unsafe操作的,所以direct的数据最终都是通过unsafe操作的)

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值