Netty源码之ByteBufAllocator
内存分配管理器有个最顶层的抽象叫做ByteBuAllocator,负责分配所有的内存,我们接下来看一下它有哪些功能:
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);
首先是三个重载的buffer,分配的内存是堆内存还是直接内存依赖与具体的实现。
/**
* 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);
三个重载的iobuffer,分配的内存是如果能直接分配直接内存就分配直接内存。
/**
* 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);
三个重载的heapBuffer,分配一块堆内存。
/**
* 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);
三个重载的directBuffer,分配一块直接内存。
接下来我们看一下他的一个抽象的实现AbstractByteBufAllocator:
public ByteBuf buffer() {
if (directByDefault) {
return directBuffer();
}
return heapBuffer();
}
刚刚我们说buffer分配内存的时候依赖具体的实现,上面的这个实现就印证了这个说法。
我们看一下是如何返回内存的,以直接内存为例:
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
validate(initialCapacity, maxCapacity);
return newDirectBuffer(initialCapacity, maxCapacity);
}
我们给他传入了一个初始容量和一个最大可以扩充到的容量,最终调用的是newDirectBuffer方法:
protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);
这个方法是一个抽象方法,根据子类是pooled还是unpooled让子类去实现,pooled是提前申请一块内存放到池中,而unpooled每次都是重新申请内存。
这个是ByteBuAllocator的继承图,接下来我们就看一下最终继承它的两大子类是如何如何实现抽象方法的:
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来返回不同的对象。创建的这两种byteBuf都是继承自AbstractReferenceCountedByteBuf,构造时的构造方法都是一样的,那么我们就要看一下unsafe和没有unsafe有什么区别:
先来看一下unsafe的
protected byte _getByte(int index) {
return UnsafeByteBufUtil.getByte(addr(index));
}
我们发现它在getByte的时候是直接通过计算出我们当前要去的字节在内存中的偏移量直接操作内存地址来获取数据的。
static byte getByte(byte[] memory, int index) {
return memory[index];
}
而另外一个测试通过数组的方式来获取数据的。这节我们就是简单的看一下这个内存分配器,在下一节我们将重点看一下PooledByteBufAllocator。