1.成员变量
先来看一下PooledByteBuf的类声明
abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf
为什么要加模版呢?
他的一个成员protected T memory;
由于不知道的T是什么数据类型,所以定义了模板类可以从他的字类中看出来
final class PooledDirectByteBuf extends PooledByteBuf<ByteBuffer>
final class PooledHeapByteBuf extends PooledByteBuf<byte[]>
在前面的学习中,很容易知道,基于内存的ByteBuf是通过操作ByteBuffer的position来实现读写等操作的,而给予堆的ByteBuf是通过Byte数组来实现读写等操作的,因此声明<T>
成员变量有
private final Recycler.Handle<PooledByteBuf<T>> recyclerHandle;
protected PoolChunk<T> chunk;
protected long handle;
protected T memory;
protected int offset;
protected int length;
int maxLength;
Thread initThread;
private ByteBuffer tmpNioBuf;
resyclerHandle可以理解为垃圾收集器,负责分配回收内存
PoolChunk<T> chunk
可以理解为一个很大的内存区域的一个实例,这个类的成员中又一个PoolArean,就是内存中的一大片区域
netty为了集中管理内存的分配和释放,同时提高分配和释放内存的性能,预先申请一大片内存,然后提供分配和释放接口来使用,这样一来,就能不需要频繁地进行系统的申请和释放内存,应用程序的性能就会大大提升。
2. 初始化
void init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength) {
assert handle >= 0;
assert chunk != null;
this.chunk = chunk;
this.handle = handle;
memory = chunk.memory;
this.offset = offset;
this.length = length;
this.maxLength = maxLength;
setIndex(0, 0);
tmpNioBuf = null;
initThread = Thread.currentThread();
}
可以知道,memory实际上就是chunk中的数据,initThread实际上就是当前的进程。
3.动态扩展内存
我们在前面的UnpooledHeapByteBuf和UnpooledDirectByteBuf中都看到了这个方法,一个是进行array的增大,一个是对ByteBuf的扩展。
public final ByteBuf capacity(int newCapacity) {
ensureAccessible();
// If the request capacity does not require reallocation, just update the length of the memory.
if (chunk.unpooled) {
if (newCapacity == length) {
return this;
}
} else {
if (newCapacity > length) {
if (newCapacity <= maxLength) {
length = newCapacity;
return this;
}
} else if (newCapacity < length) {
if (newCapacity > maxLength >>> 1) {
if (maxLength <= 512) {
if (newCapacity > maxLength - 16) {
length = newCapacity;
setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
return this;
}
} else { // > 512 (i.e. >= 1024)
length = newCapacity;
setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
return this;
}
}
} else {
return this;
}
}
1.如果chunk内存区是unpooled(没有实现内存池)的话,只有当newCapacity == length
时直接返回,其他情况都要重新分配内存。
2.如果chunk内存区实现了内存池,当新的容量大于原来的容量,且小于最大容量时,直接设置原来的容量为新的容量就行。
3.如果新的容量小于原来的容量,那么就要进行减容处理了,先把最大容量>>>1,向右位位移一位(除2),然后根据除2以后的最大容量和新容量对比,分别进行不同的操作。
4.分配回收内存
来看三个方法
@Override
public final ByteBufAllocator alloc() {
return chunk.arena.parent;
}
@Override
protected final void deallocate() {
if (handle >= 0) {
final long handle = this.handle;
this.handle = -1;
memory = null;
boolean sameThread = initThread == Thread.currentThread();
initThread = null;
chunk.arena.free(chunk, handle, maxLength, sameThread);
recycle();
}
}
private void recycle() {
recyclerHandle.recycle(this);
}
第一个方法返回ByteBufAllocator对象
第二个方法先销毁原来的内存区,然后重新分配
第三个方法直接回收内存区