追寻水中桥 2019-10-19
PooledByteBuf的初始化过程分为两个步骤:创建实例;初始化内存。这两个步骤的代码如下:
protected PooledByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) { super(maxCapacity); this.recyclerHandle = recyclerHandle; } void init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache cache) { init0(chunk, handle, offset, length, maxLength, cache); } private void init0(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache cache) { assert handle >= 0; assert chunk != null; this.chunk = chunk; memory = chunk.memory; allocator = chunk.arena.parent; this.cache = cache; this.handle = handle; this.offset = offset; this.length = length; this.maxLength = maxLength; tmpNioBuf = null; }
创建实例时调用的构造方法只是为maxCapacity和recyclerHandler属性赋值,构造方法是protected,不打算暴露到外面。派生类都提供了newInstance方法创建实例,以PooledHeapByteBuf为例,它的newInstance方法实现如下:
private static final Recycler<PooledHeapByteBuf> RECYCLER = new Recycler<PooledHeapByteBuf>() { @Override protected PooledHeapByteBuf newObject(Handle handle) { return new PooledHeapByteBuf(handle, 0); } }; static PooledHeapByteBuf newInstance(int maxCapacity) { PooledHeapByteBuf buf = RECYCLER.get(); buf.reuse(maxCapacity); return buf; }
这里的newInstance使用RECYCLER创建实例对象。Recycler<T>是一个轻量级的,支持循环使用的对象池。当对象池中没有可用对象时,会在第4行使用构造方法创建一个新的对象。
init调用init0初始化数据内存,init0方法为几个内存相关的关键属性赋值:
内存初始化完成之后,这个PooledByteBuf可使用的内存范围是memory内存中[offset, offset+length)。idx方法可以把ByteBuf的索引转换成memory的索引:
1 protected final int idx(int index) { 2 return offset + index; 3 }
和前面讲过的ByteBuf实现一样,PooledByteBuf也需要使用capacity(int newCapacity)改变内存大小,也会涉及到把数据从旧内存中复制到新内存的问题。也就是说,要解决的问题是一样的,只是具体实现的差异。
@Override public final ByteBuf capacity(int newCapacity) { checkNewCapacity(newCapacity); // 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; } } // Reallocation required. chunk.arena.reallocate(this, newCapacity, true); return this; }