netty中重新封装了buffer,于是ByteBuf出现了。
public interface ByteBuf extends ChannelBuf, Comparable<ByteBuf> { public ByteBufAllocator alloc(); public byte[] array(); public int arrayOffset(); public int bytesBefore(byte); public int bytesBefore(ByteBufIndexFinder); public int bytesBefore(int, byte); public int bytesBefore(int, ByteBufIndexFinder); public int bytesBefore(int, int, byte); public int bytesBefore(int, int, byteBufIndexFinder); public int capacity(); public ByteBuf capacity(int); public ByteBuf clear(); public int compareTo(ByteBuf); public ByteBuf copy(); public ByteBuf copy(int, int); public ByteBuf discardReadBytes(); public ByteBuf duplicate(); public ByteBuf ensureWritableBytes(int); public ByteBuf ensureWritableBytes(int, boolean); public boolean equals(Object); ... }
实在是太多,不一一罗列。这里注意的是,readerIndex()和writerIndex()说明有两个指针,这样的话,在0和readerIndex()之间的数据就表示已经读过的,调用discardReadBytes()就可以删除这些数据,类似NIO中的compact
这样做的好处是减少不必要的拷贝。指针是个宝。
当然这里的ByteBuf也把ByteBuffer中该有的都不落下。同时看接口,ChannelBuf只是一个方法 type()返回表明是byte还是message数据。comparable大家都很熟悉了。
ByteBuf是个接口,她有两个子接口
CompositeByteBuf 和 UnsafeByteBuf
CompositeByteBuf 就是多个ByteBuf的组合。
UnsafeByteBuf则是增加了一些方法,可以操作NIO。
接下来有 AbstractByteBuf,ReplayingDecoderBuffer和SwappedByteBuf
当然这些都不怎么用,SwappedByteBuf直接把传入的ByteBuf的字节序弄反就是了。
ReplayingDecoderBuffer则是在terminate以后,才返回capacity,这样可以用于在接受数据时,如果数据接收齐全了,就使用terminate()函数。
在AbstractByteBuf的强大实现下,开始有很多的子类了。大家可以看看。
这里要说常用的。例如UnpooledHeapByteBuf和UnpooledDirectByteBuf
这两个类基本上就是ByteBuf的实现类,工具类UnpooledByteBufAllocator正是通过返回他们得到想要的ByteBuf实例。文档上建议我们使用Unpooled工具类来创建这些ByteBuf,例如 directBuffer() 或者 wrappedBuffer(byte[]),wrappedBuffer(ByteBuffer) 等。
UnpooledDirectByteBuf很有意思,请看
private static final Field CLEANER_FIELD; static { ByteBuffer direct = ByteBuffer.allocateDirect(1); Field cleanerField; try { cleanerField = direct.getClass().getDeclaredField("cleaner"); cleanerField.setAccessible(true); Cleaner cleaner = (Cleaner) cleanerField.get(direct); cleaner.clean(); } catch (Throwable t) { cleanerField = null; } CLEANER_FIELD = cleanerField; }
这里正是NIO中一个头疼的问题,就是direct memory的回收。这里给出一个解决办法。通常我们都是使用了System.gc()去建议JVM回收。
下面是使用。
private static void freeDirect(ByteBuffer buffer) { if (CLEANER_FIELD == null) { // Doomed to wait for GC. return; } Cleaner cleaner; try { cleaner = (Cleaner) CLEANER_FIELD.get(buffer); cleaner.clean(); } catch (Throwable t) { // Nothing we can do here. } }
netty4.0 buffer,使用了读写指针直接对byte进行封装。并没有在NIO的buffer上再次封装,对于NIO buffer,则是直接使用byte array包装。