我们分三部分讲解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后面文章会继续讲解。