netty源码阅读之ByteBuf之内存分配器ByteBufAllocator

我们分三部分讲解ByteBufAllocator:

1、ByteBufAllocator功能

2、AbstractByteBufAllocator

3、ByteBufAllocator两大子类

 

一、ByteBufAllocator功能

查看ByteBufAllocator源码:


/**
 * Implementations are responsible to allocate buffers. Implementations of this interface are expected to be
 * thread-safe.
 */
public interface ByteBufAllocator {

    ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;

    /**
     * Allocate a {@link ByteBuf}. If it is a direct or heap buffer
     * depends on the actual implementation.
     */
    ByteBuf buffer();

    /**
     * Allocate a {@link ByteBuf} with the given initial capacity.
     * If it is a direct or heap buffer depends on the actual implementation.
     */
    ByteBuf buffer(int initialCapacity);

    /**
     * Allocate a {@link ByteBuf} with the given initial capacity and the given
     * maximal capacity. If it is a direct or heap buffer depends on the actual
     * implementation.
     */
    ByteBuf buffer(int initialCapacity, int maxCapacity);

    /**
     * Allocate a {@link ByteBuf}, preferably a direct buffer which is suitable for I/O.
     */
    ByteBuf ioBuffer();

    /**
     * Allocate a {@link ByteBuf}, preferably a direct buffer which is suitable for I/O.
     */
    ByteBuf ioBuffer(int initialCapacity);

    /**
     * Allocate a {@link ByteBuf}, preferably a direct buffer which is suitable for I/O.
     */
    ByteBuf ioBuffer(int initialCapacity, int maxCapacity);

    /**
     * Allocate a heap {@link ByteBuf}.
     */
    ByteBuf heapBuffer();

    /**
     * Allocate a heap {@link ByteBuf} with the given initial capacity.
     */
    ByteBuf heapBuffer(int initialCapacity);

    /**
     * Allocate a heap {@link ByteBuf} with the given initial capacity and the given
     * maximal capacity.
     */
    ByteBuf heapBuffer(int initialCapacity, int maxCapacity);

    /**
     * Allocate a direct {@link ByteBuf}.
     */
    ByteBuf directBuffer();

    /**
     * Allocate a direct {@link ByteBuf} with the given initial capacity.
     */
    ByteBuf directBuffer(int initialCapacity);

    /**
     * Allocate a direct {@link ByteBuf} with the given initial capacity and the given
     * maximal capacity.
     */
    ByteBuf directBuffer(int initialCapacity, int maxCapacity);

    /**
     * Allocate a {@link CompositeByteBuf}.
     * If it is a direct or heap buffer depends on the actual implementation.
     */
    CompositeByteBuf compositeBuffer();

    /**
     * Allocate a {@link CompositeByteBuf} with the given maximum number of components that can be stored in it.
     * If it is a direct or heap buffer depends on the actual implementation.
     */
    CompositeByteBuf compositeBuffer(int maxNumComponents);

    /**
     * Allocate a heap {@link CompositeByteBuf}.
     */
    CompositeByteBuf compositeHeapBuffer();

    /**
     * Allocate a heap {@link CompositeByteBuf} with the given maximum number of components that can be stored in it.
     */
    CompositeByteBuf compositeHeapBuffer(int maxNumComponents);

    /**
     * Allocate a direct {@link CompositeByteBuf}.
     */
    CompositeByteBuf compositeDirectBuffer();

    /**
     * Allocate a direct {@link CompositeByteBuf} with the given maximum number of components that can be stored in it.
     */
    CompositeByteBuf compositeDirectBuffer(int maxNumComponents);

    /**
     * Returns {@code true} if direct {@link ByteBuf}'s are pooled
     */
    boolean isDirectBufferPooled();

    /**
     * Calculate the new capacity of a {@link ByteBuf} that is used when a {@link ByteBuf} needs to expand by the
     * {@code minNewCapacity} with {@code maxCapacity} as upper-bound.
     */
    int calculateNewCapacity(int minNewCapacity, int maxCapacity);
 }

前面几个方法buffer和ioBuffer就是分配buffer或者ioBuffer,至于分配什么buffer,direct的还是heap的,由具体实现决定。

后面就有heapBuffer和directBuffer就是分配堆内内存和堆外内存了,既然如此,为什么还要上面的buffer方法?看到后面的AbstractByteBufAllocator就真相大白,其实先调用buffer方法,再在这个方法里面地调用heapBufffer和directBuffer。

ps:这里我们先留意一下,netty如何区分heapBuffer还是directBuffer,就是通过这里区分的。第三点的时候回继续分析别的。

 

最后的compositeBuffer那就是分配堆内内存和堆外内存都有的buffer了

 

二、AbstractByteBufAllocator

ByteBufAllocator的骨架式实现AbstractByteBufAllocator,都是这个套路。

看它实现的buffer方法:

   @Override
    public ByteBuf buffer() {
        if (directByDefault) {
            return directBuffer();
        }
        return heapBuffer();
    }

调用directBuffer或者heapBuffer方法,上面说的没错吧。随便看一个directBuffer,一直进去:

   @Override
    public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
        if (initialCapacity == 0 && maxCapacity == 0) {
            return emptyBuf;
        }
        validate(initialCapacity, maxCapacity);
        return newDirectBuffer(initialCapacity, maxCapacity);
    }

看newDirectBuffer(initialCapacity,maxCapacity):

    /**
     * Create a direct {@link ByteBuf} with the given initialCapacity and maxCapacity.
     */
    protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);

它没有实现,留给它的子类去实现。

同理,newHeapBuffer也留给它的子类去实现,它有两个子类:

PooledByteBufAllocator和UnpooledByteBufAllocator

PooledByteBufAllocator相当于在预先分配好的内存里面取一段,而UnpooledByteBufAllocator相当于直接调用系统API去分配内存。

AbstractByteBufAllocator 暴露两个接口让子类去实现:newHeapBuffer、newDirectBuffer

 

三、ByteBufAllocator两大子类

先看一个类图:

PooledByteBufAllocator和UnpooledByteBufAllocator,我们现在知道,netty区分unpooled还是pooled的buffer是通过allocator的子类PooledByteBufAllocator和UnpooledByteBufAllocator去实现的;而通过第一点我们知道,区分heap还是direct的buffer是通过内存分配器ByteBufAllocator自己的方法去实现的;从上一篇文章最后我们也知道是否unsafe是由jdk底层去实现的,如果能够获取到unsafe对象,就使用unsafe。

 

事不宜迟,我们先从UnpooledByteBufAllocator上一段没有结束的newHeapBuffer进入,进入实现的源码:


    @Override
    protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
        return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
                : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
    }

从 new UnpooledUnsafeHeapByteBuf()进入:

    /**
     * Creates a new heap buffer with a newly allocated byte array.
     *
     * @param initialCapacity the initial capacity of the underlying byte array
     * @param maxCapacity the max capacity of the underlying byte array
     */
    UnpooledUnsafeHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
        super(alloc, initialCapacity, maxCapacity);
    }

继续:

    /**
     * Creates a new heap buffer with a newly allocated byte array.
     *
     * @param initialCapacity the initial capacity of the underlying byte array
     * @param maxCapacity the max capacity of the underlying byte array
     */
    protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
        this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);
    }

我们可以知道,heap数据都是存放在byte数组里面的,而且UnpooledUnsafeHeapByteBuf的父类是UnpooledHeapByteBuf(而且我们可以知道UnpooledUnsafeHeapByteBuf是直接调用父类UnpooledHeapByteBuf的方法创建的,UnpooledUnsafeHeapByteBuf创建的时候相当于创建了一个UnpooledHeapByteBuf),那么继续吧:

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

setArray(initialArray):

   private void setArray(byte[] initialArray) {
        array = initialArray;
        tmpNioBuf = null;
    }

setIndex(readerIndex,writerIndex):

    @Override
    public ByteBuf setIndex(int readerIndex, int writerIndex) {
        if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {
            throw new IndexOutOfBoundsException(String.format(
                    "readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex <= writerIndex <= capacity(%d))",
                    readerIndex, writerIndex, capacity()));
        }
        setIndex0(readerIndex, writerIndex);
        return this;
    }

    final void setIndex0(int readerIndex, int writerIndex) {
        this.readerIndex = readerIndex;
        this.writerIndex = writerIndex;
    }

都是一目了然,无需多分析。我们再重申一遍,创建UnpooledHeapByteBuf的时候底层是一个数组(array)

我们现在是unsafe的,那个刚刚在setArray方法设置进去的array就在_getByte(int index)的时候传入进去了:

    @Override
    protected byte _getByte(int index) {
        return UnsafeByteBufUtil.getByte(array, index);
    }

后面的继续深入,我们在之前的文章也分析过。

在这里我们再次理解一下,UnpooledHeapByteBuf和UnpooledUnsafeHeapByteBuf存储的时候,都是通过一个array。但是_getByte(array,index)的时候,UnpooledHeapByteBuf底层是直接操作array:

    @Override
    protected byte _getByte(int index) {
        return HeapByteBufUtil.getByte(array, index);
    }
    static byte getByte(byte[] memory, int index) {
        return memory[index];
    }

而 UnpooledUnsafeHeapByteBuf是通过UNSAFE操作这个数组:

    @Override
    protected byte _getByte(int index) {
        return UnsafeByteBufUtil.getByte(array, index);
    }
    static byte getByte(byte[] data, int index) {
        return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
    }

 

另外PooledByteBufAllocator后面文章会继续讲解。

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值