netty 零拷贝

首先将它与传统的I/O read和write操作作对比,看看有什么不同,首先需要理解一下用户态和内存态的概念

用户态(User Mode)和内核态(Kernel Mode),也可以叫用户空间和内核

用户态:受限的访问内存,并且不允许访问硬件设备。

内核态:本质上是一个软件,可以控制计算机的硬件资源(如网卡,硬盘),可以访问内存所有数据。


用户程序都是运行在用户态中的,比如JVM,就是用户程序,所以它运行在用户态中。

用户态是不能直接访问硬件设备的,如果需要一次I/O操作,那就必须利用系统调用机制切换到内核态(用户态与内核态之间的转换称为上下文切换),进行硬盘读写。

比如说一次传统网络I/O:

第一步,从用户态切换到内核态,将用户缓冲区的数据拷贝到内核缓冲区,执行send操作。

第二步,数据发送由底层的操作系统进行,此时从内核态切换到用户态,将内核缓存区的数据拷贝到网卡的缓冲区

总结:也就是一次普通的网络I/O,至少经过两次上下文切换,和两次内存拷贝。


什么是零拷贝?

当需要传输的数据远大于内核缓冲区的大小时,内核缓冲区就成为I/O的性能瓶颈。零拷贝就是杜绝了内核缓冲区与用户缓冲区的的数据拷贝。

所以零拷贝适合大数据量的传输。

拿传统的网络I/O做对比,零拷贝I/O是怎样的一个过程:

用户程序执行transferTo(),将用户缓冲区待发送的数据拷贝到网卡缓冲区。

很简单,一步完成,中间少了用户态到内存态的拷贝。

 

Netty中零拷贝如何实现

Netty的中零拷贝与上述零拷贝是不一样的,它并不是系统层面上的零拷贝,只是相对于ByteBuf而言的。

Netty中的零拷贝:

1.CompositeByteBuf,将多个ByteBuf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的拷贝。

使用方式:

CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();

compositeByteBuf.addComponents(true, ByteBuf1, ByteBuf1);


注意:addComponents第一个参数必须为true,那么writeIndex才不为0,才能从compositeByteBuf中读到数据。


2.wrapedBuffer()方法,将byte[]数组包装成ByteBuf对象。


byte[] bytes = data.getBytes();

ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);


 Unpooled.wrappedBuffer(bytes)就是进行了byte[]数组的包装工作,过程中不存在内存拷贝。

即包装出来的ByteBuf和byte[]数组指向了同一个存储空间。因为值引用,所以bytes修改也会影响byteBuf 的值。


3.ByteBuf的分割,slice()方法。将一个ByteBuf对象切分成多个ByteBuf对象。

ByteBuf directByteBuf = ByteBufAllocator.DEFAULT.directBuffer(1024);

ByteBuf header = directByteBuf.slice(0,50);

ByteBuf body = directByteBuf.slice(51,1024);

header和body两个ByteBuf对象实际上还是指向directByteBuf的存储空间。


转自https://www.cnblogs.com/superfj/p/9242968.html

你可能感兴趣的:(netty 零拷贝)