您的位置:首页 > 其它

Netty-ByteBuf学习3

2019-03-31 22:50 381 查看

版权声明:本文为博主原创文章,转载请注明出处
UnpooledHeapByteBuf源码分析
从类名中就可以看出,当前类是采用的堆内存的形式的字节缓冲区,并且没有基于对象池技术来实现

成员变量中,alloc的类型是ByteBufAllocator,用于为UnpooledHeapByteBuf分配堆内存;byte类型的数组作为缓冲区;tmpNioBuf的类型是ByteBuffer ,用于实现ByteBuf到ByteBuffer的转换

private final ByteBufAllocator alloc;
byte[] array;
private ByteBuffer tmpNioBuf;

在AbstractByteBuf类中实现了当写入的字节数不够时依照怎样的规则去重新计算新容量的方法,在本类中实现的是依照返回的新容量去重新分配数组。首先检查newCapacity,内部实现是先去判断checkBounds,即是否需要检查界限,如果需要再去判断newCapacity是否大于0或小于最大容量;然后获得当前byte数组的长度oldCapacity,判断newCapacity和oldCapacity的关系;如果大于,说明,需要重新分配一个数组,将旧数组中的值拷贝到新数组中,并设置新数组和释放旧数组,此时不需要;如果小于,也需要重新分配一个数组,获取当前缓冲区的读指针readerIndex,判断readerIndex和newCapacity的关系,如果小于,再判断写指针writerIndex和newCapacity,如果大于,说明写指针超出了范围,需要将写指针赋值为writerIndex,然后将旧数组中读指针到写指针之间的数据拷贝到新数组中,这是用户还没读取的内容;如果readerIndex>=newCapacity,直接将读写指针都设置为newCapacity,然后设置新数组并释放旧数组

public ByteBuf capacity(int newCapacity) {
checkNewCapacity(newCapacity);

int oldCapacity = array.length;
byte[] oldArray = array;
if (newCapacity > oldCapacity) {
byte[] newArray = allocateArray(newCapacity);
System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
setArray(newArray);
freeArray(oldArray);
} else if (newCapacity < oldCapacity) {
byte[] newArray = allocateArray(newCapacity);
int readerIndex = readerIndex();
if (readerIndex < newCapacity) {
int writerIndex = writerIndex();
if (writerIndex > newCapacity) {
writerIndex(writerIndex = newCapacity);
}
System.arraycopy(oldArray, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
} else {
setIndex(newCapacity, newCapacity);
}
setArray(newArray);
freeArray(oldArray);
}
return this;
}

将ByteBuf转换为NIO中的ByteBuffer的方法,直接使用ByteBuffer中wrap方法,设置好读写位置和容量,然后调用slice方法返回当前缓冲区的透视,即读写索引等变量都是独立的,但是缓冲区内容是共享的。

public ByteBuffer nioBuffer(int index, int length) {
ensureAccessible();
return ByteBuffer.wrap(array, index, length).slice();
}

PooledDirectByteBuf源码分析

PooledDirectByteBuf与UnpooledDirectByteBuf只是内存分配策略不同,其它功能均相同

由于本类使用了内存池来实现,所以创建一个新对象不需要在内存中新开辟一个地址,需要从RECYCLER中获取,然后设置引用计数值

static PooledDirectByteBuf newInstance(int maxCapacity) {
PooledDirectByteBuf buf = RECYCLER.get();
buf.reuse(maxCapacity);
return buf;
}

下述copy方法返回一个新的ByteBuf的实例,主要是调用AbstractByteBufAllocator的directBuffer方法,方法里newDirectBuffer会根据AbstractByteBufAllocator不同的子类实现不同的调用,例如如果是基于内存池的实现,那么会从内存池中选取一个实例并进行赋值返回,否则会新申请一个内存。

public ByteBuf copy(int index, int length) {
checkIndex(index, length);
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
copy.writeBytes(this, index, length);
return copy;
}

PooledDirectByteBuf中newDirectBuffer方法的实现。首先取得一个分配内存线程池中的一个实例,获得directArena,然后当directArena不为null时,直接调用allocate返回ByteBuf的一个实例;否则判断当前平台是否有Unsafe的实现,有的话调用UnsafeByteBufUtil的newUnsafeDirectByteBuf方法,否则调用UnpooledDirectByteBuf构造方法

protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<ByteBuffer> directArena = cache.directArena;

final ByteBuf buf;
if (directArena != null) {
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {
buf = PlatformDependent.hasUnsafe() ?
UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}

return toLeakAwareBuffer(buf);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: