Netty的ByteBuf介绍

Netty的ByteBuf缓冲区实现地比Java本身的ByteBuffer更加灵活,方便。它的类结构也比较复杂,这里只说ByteBuf核心的几个要点。

1. 最重要的是要理解为什么要ByteBuf这个组件。主要还是因为基于select / poll / epoll这种IO多路复用技术的NIO是非阻塞同步IO的模型,由于是同步IO,需要用户线程自己来处理IO的读写,由于是非阻塞的,每次调用read, write读写的字节数是不确定的,所以非阻塞同步IO必须有缓冲区这个组件来保存每次读写的中间状态,通过缓冲区来确定是否读写完成。更多内容请参考http://blog.csdn.net/iter_zc/article/details/39291647

2. ByteBuf不是对ByteBuffer的封装,而是重新实现了一个缓冲区。ByteBuffer只使用了一个position指针来记录当前的读写位置,ByteBuf使用了两个指针readerIndex, writerIndex分别来记录当前的读写位置,使用起来更加简单和方便。

3. ByteBuffer是一个固定长度的缓冲区,当put方法要写的数据大于可写的容量时会抛出异常。ByteBuf改进了这个设计,支持自动扩容。每次put之前会检查是否可以完全写入,如果不能,就会自动扩展ByteBuf的容量,保证put方法不会抛出异常。

public ByteBuf writeInt(int value) {	ensureWritable(4);	_setInt(writerIndex, value);	writerIndex += 4;	return this;} public ByteBuf ensureWritable(int minWritableBytes) {	if (minWritableBytes < 0) {	throw new IllegalArgumentException(String.format(		"minWritableBytes: %d (expected: >= 0)", minWritableBytes));	}	if (minWritableBytes <= writableBytes()) {	return this;	}	if (minWritableBytes > maxCapacity - writerIndex) {	throw new IndexOutOfBoundsException(String.format(		"writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",		writerIndex, minWritableBytes, maxCapacity, this));	}	// Normalize the current capacity to the power of 2.	int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);	// Adjust to the new capacity.	capacity(newCapacity);	return this;}//UnpooledHeapByteBuf的capacity方法来自动扩容public ByteBuf capacity(int newCapacity) {	ensureAccessible();	if (newCapacity < 0 || newCapacity > maxCapacity()) {	throw new IllegalArgumentException("newCapacity: " + newCapacity);	}	int oldCapacity = array.length;	if (newCapacity > oldCapacity) {	byte[] newArray = new byte[newCapacity];	System.arraycopy(array, 0, newArray, 0, array.length);	setArray(newArray);	} else if (newCapacity < oldCapacity) {	byte[] newArray = new byte[newCapacity];	int readerIndex = readerIndex();	if (readerIndex < newCapacity) {		int writerIndex = writerIndex();		if (writerIndex > newCapacity) {		writerIndex(writerIndex = newCapacity);		}		System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);	} else {		setIndex(newCapacity, newCapacity);	}	setArray(newArray);	}	return this;}private void setArray(byte[] initialArray) {	array = initialArray;	tmpNioBuf = null;}

4. 和ByteBuffer一样,ByteBuf也支持堆内缓冲区和堆外直接缓冲区,根据经验来说,底层IO处理线程的缓冲区使用堆外直接缓冲区,减少一次IO复制。业务消息的编解码使用堆内缓冲区,分配效率更高,而且不涉及到内核缓冲区的复制问题。

5. ByteBuf的堆内缓冲区又分为内存池缓冲区PooledByteBuf和普通内存缓冲区UnpooledHeapByteBuf。PooledByteBuf采用二叉树来实现一个内存池,集中管理内存的分配和释放,不用每次使用都新建一个缓冲区对象。UnpooledHeapByteBuf每次都会新建一个缓冲区对象。在高并发的情况下推荐使用PooledByteBuf,可以节约内存的分配。在性能能够保证的情况下,可以使用UnpooledHeapByteBuf,实现比较简单。

猜你喜欢

转载自eric-hwp.iteye.com/blog/2255508