美文网首页程序员
Netty中的字节操作

Netty中的字节操作

作者: whthomas | 来源:发表于2016-05-10 22:12 被阅读3403次

Netty作为一个优秀网络框架,其高效的内存操作也是使其变得高性能的很重要原因之一。

众所周知,JavaNIO中提供了类ByteBuffer作为字节的容器,但是操作非常的复杂,Netty针对ByteBuffer设计了一个替代类ByteBuf,方便开发者操作字节。

ByteBuf API

对于任意一个ByteBuf对象,都拥有三个非常重要的属性:

  1. readerIndex:读索引
  2. writerIndex:写索引
  3. capacity:对象容量

ByteBuf对象每读取一个byte的数据,readerIndex就会往前推进,直到readerIndex到达capacity的值,所有的数据的数据都被读取完,ByteBuf不可再被读取。可以通过readableBytes()方法获取readerIndex的值。

相同地,writerIndex记录了ByteBuf对象使用了多少数据,可以通过writableBytes()方法获取writerIndex的值。每当ByteBuf被写入了多少数据,writerIndex就会往前推进,直到值到达capacity的值,ByteBuf会自动对空间进行扩容。

对于任意一个ByteBuf对象,我们都可以根据它的索引通过getByte()方法随机访问中间的数据。随机访问不会改变readerIndex的值。

通过array()方法可以直接获取,ByteBuf中的Byte数组信息。

几种ByteBuf模式

Netty的“Zero-Copy”设计非常出名,这主要就是依赖了Netty中ByteBuf的设计。ByteBuf主要有以下几种模式:

1.Heap Buffer模式

顾名思义,这个模式下的字节是在Jvm的堆区操作的,也是最常见的内存操作了。

2.Direct Buffer模式

在JDK1.4中,Java引入了一种直接内存,NIO可以通过本地方法分配一些堆外的直接内存,这块内存区不受Jvm的控制,理论上的无限的。

对于网络Socket通信来说,这种内存区域的好处是Java在通信中,数据不必从Jvm中拷贝一份到系统的直接内存区上,操作系统的Socket接口可以直接处理这份在直接内存的数据。同时由于数据在堆外,也避免了频繁GC对这块区域的影响。

ByteBuf提供了Direct Buffer模式,我们可以直接通过ByteBuf操作直接内存

Direct Buffer模式下,由于数据不在堆上面,ByteBuf是不可以直接使用array()方法获取数据的。

3.Composite buffer模式

在TCP协议中,一份完整的数据总是被拆成好几个包被发送或者接收,一般情况下,程序会通过内存拷贝的方式将一组数据拷贝到一个大的数组中,形成一份完整的数据。

而Composite buffer模式可以聚合多个ByteBuffer对象,将这组数据的引用收集到一个ByteBuf对象中,避免了数据的拷贝。

// 初始化一个Composite buffer模式的`ByteBuf`
CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer(size);

// 添加byteBuf对象
compositeByteBuf.addComponent(byteBuf1);
compositeByteBuf.addComponent(byteBuf2);
compositeByteBuf.addComponent(byteBuf3);

// 操作compositeByteBuf
handle(compositeByteBuf);

分配内存的方式

当然为了避免Netty本身内存使用过度,Netty内部对所有的内存做了池化。通过ByteBufAllocator类,我们可以分配一块被池化的内存,从而减少分配和释放内存的开销。

ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
ByteBuf buffer = ByteBufAllocator.DEFAULT.heapBuffer();
ByteBuf buffer = ByteBufAllocator.DEFAULT.ioBuffer();
ByteBuf buffer = ByteBufAllocator.DEFAULT.directBuffer();
ByteBuf buffer = ByteBufAllocator.DEFAULT.compositeBuffer();

如果我们希望使用一块新的内存,或者对一个已经存在的内存进行包装,那么我们可以使用Unpooled类来分配内存:

 ByteBuf heapBuffer    = buffer(128);
 ByteBuf directBuffer  = directBuffer(256);
 ByteBuf wrappedBuffer = wrappedBuffer(new byte[128], new byte[256]);
 ByteBuf copiedBuffe r = copiedBuffer(ByteBuffer.allocate(128));

相关文章

网友评论

    本文标题:Netty中的字节操作

    本文链接:https://www.haomeiwen.com/subject/fmbyrttx.html