Netty零拷贝
Netty的零拷贝完全是在用户态(Java 层面)的, 它的零拷贝更多的是偏向于 优化数据操作 这样的概念.而不是操作系统层面的用户态和核心态之间的数据拷贝。
Netty 的 零拷贝体现在如下几个个方面:
Netty 提供了 CompositeByteBuf 类, 它可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf, 避免了各个 ByteBuf 之间的拷贝.
通过 wrap 操作, 我们可以将 byte[] 数组、ByteBuf、ByteBuffer等包装成一个 Netty ByteBuf 对象, 进而避免了拷贝操作.
ByteBuf 支持 slice 操作, 因此可以将 ByteBuf分解为多个共享同一个存储区域的 ByteBuf, 避免了内存的拷贝.
通过 FileRegion 包装的FileChannel.tranferTo 实现文件传输, 可以直接将文件缓冲区的数据发送到目标 Channel, 避免了传统通过循环 write 方式导致的内存拷贝问题.
ButeBuffer
Java NIO提供ByteBuffer作为字节容器,但只有一个位置指针用于处理读写操作,每次读写时候都需要额外调用flip()和clear()方法,否则功能将会出错。查看ByteBuffer源码如下:
mark:调用mark()方法的话,mark值将存储当前position的值,等下次调用reset()方法时,会设定position的值为之前的标记值;
position:是下一个要被读写的元素的数组下标索引,该值会随get()和put()的调用自动更新;
limit:是缓冲区中第一个不能读写的元素的数组下标索引,也可以认为是缓冲区中实际元素的数量;
capacity:是缓冲区能够容纳元素的最大数量,这个值在缓冲区创建时被设定,而且不能够改变
四者关系如下:
0 <=mark <= position <= limit <= capacity
ByteBuffer bf = ByteBuffer.allocate(10);
创建初始化缓冲区,可以看到初始值position=0,而limit=capacity=初始化长度
调用flit刷新缓冲区为读模式
bf.flip()
缓冲区有两种模式,分别是写模式和读模式,这两种模式通过使用flip方法进行模式。如上将缓冲区切换为读模式,则position变成了初值位置0,而limit变成了写模式下position位置。
读取缓冲区中到内容:get()
调用mark(),标记position位置
标记完position后,继续读取缓冲区区内容
使用reset()方法可以使position回到mark存储到位置
调用compact()方法,清空已读取数据空间,进行数据到重新填充
使用clear清空缓冲区
ByteBuf详解
从结构上来说,ByteBuf 由一串字节数组构成。数组中每个字节用来存放信息。
ByteBuf是Netty框架封装的数据缓冲区,区别于ByteBuffer需要有position、limit、flip等属性和操作来控制byteBuffer数据读写,Bytebuf通过两个位置指针来协助缓冲区的读写操作,分别是readIndex和writerIndex。
当从 ByteBuf 读取时,它的 readerIndex(读索引)将会根据读取的字节数递增。 同样,当写 ByteBuf 时,它的
writerIndex 也会根据写入的字节数进行递增
需要注意的是极限的情况是 readerIndex 刚好读到了 writerIndex 写入的地方。
如果 readerIndex 超过了 writerIndex 的时候,Netty 会抛出 IndexOutOf-BoundsException 异常。
初始化ByteBuf时,readIndex和writerIndex取值一开始是0,随着数据的写入writerIndex会增加,读取数据会使readIndex增加,但不会超过writerIndex。在读取之后0-readIndex被视为discard,调用discardReadBytes方法,释放这部分空间,作用类似于ByteBuffer的compact方法,移除无用数据,实现缓冲区的重复使用
初始化ByteBuf ByteBuf bf= Unpooled.buffer(10,100)
读取数据 read
写入数据 write
discardReadBytes 释放已经读取过的数据空间
相比较,Netty中的ByteBuf使用更加方便,还提供了查找操作(indexOf(int fromindex,int toIndex,byte value)、bytesBefore(Byte value))、数据复制(Derived buffers)、ByteBuffer和ByteBuf互相转化等功能更强大的方法。