当前位置:网站首页>NIO 零拷贝
NIO 零拷贝
2022-06-24 19:34:00 【Nice2cu_Code】
零拷贝
一、传统IO的问题
将服务器中的文件内容,通过 socket 的 API,发送到客户端:
File f = new File("helloword/data.txt");
RandomAccessFile file = new RandomAccessFile(file, "r");
//将数据从文件读取到byte数组中
byte[] buf = new byte[(int)f.length()];
file.read(buf);
//将数据从byte数组写出到网络socket
Socket socket = ...;
socket.getOutputStream().write(buf);
读写操作的内部工作流程如下:

java 本身并不具备 IO 读写能力,因此 read 方法调用后,要从 java 程序的用户态切换至内核态,去调用操作系统的读能力,将数据读入内核缓冲区。这期间用户线程阻塞,操作系统使用 DMA 来实现文件的读操作(期间不会使用 CPU)
DMA 可以理解为专门用来负责数据传输的硬件,不会利用CPU时间
从内核态切换回用户态,将数据从内核缓冲区读入用户缓冲区(即
byte[] buf),这期间 CPU 会参与拷贝,无法利用 DMA调用 write 方法,将数据从用户缓冲区写入 socket缓冲区,CPU 会参与拷贝
接下来要向网卡写数据,这项能力 java 也不具备,因此又得从用户态切换至内核态,调用操作系统的写能力,使用 DMA 将 socket缓冲区 的数据写入网卡,不会使用 CPU
可以看到传统IO存在的问题:
- 用户态与内核态的切换发生了 3 次,这个操作比较重量级
- 数据拷贝了 4 次
二、NIO优化
NIO优化是通过使用直接内存
DirectByteBuffer调用
ByteBuffer.allocateDirect(10),返回的DirectByteBuffer使用的是操作系统内存,java 层面和操作系统都可以访问到- 调用
ByteBuffer.allocate(10),返回的HeapByteBuffer使用的是 java 内存
- 调用
读写过程如下所述:

大部分步骤与优化前相同,不再赘述。
不同点:内核缓冲区和用户缓冲区,共用一块内存 DirectByteBuffer ,减少了一次数据的拷贝。
用户态与内核态的切换次数没有减少。
1. Linux 2.1 优化(零拷贝)
采用了 Linux 2.1 后提供的 sendFile 方法,在 java 中对应着两个方法可以调用到 sendFile 方法:
- channel 调用
transferTo/transferFrom方法拷贝数据
读写过程如下所述:

第2步中,内核缓冲区中的数据无需写入数组或直接内存,通过调用 sendFile 方法直接将数据写入到 socket 缓冲区,不经过 java 层面(少了两次内核态和用户态的切换)。
注意:数据从内核缓冲区传输到 socket 缓冲区,CPU 会参与拷贝。
只发生了一次用户态与内核态的切换,数据拷贝了 3 次。
2. Linux 2.4 优化(零拷贝)
底层依然采用了 linux 2.1 后提供的 sendFile 方法。
读写过程如下所述:

内核缓冲区的数据可直接写入到网卡。
只会将内核缓冲区中的少量 offset 和 length 信息拷入 socket 缓冲区,几乎无消耗。
整个过程只发生了一次用户态与内核态的切换,数据拷贝了 2 次。
三、零拷贝
调用 linux 2.1 后提供的 sendFile 方法的拷贝都可以称为零拷贝。
所谓的零拷贝,并不是没有拷贝操作,而是不会将数据拷贝到 Java 内存中,零拷贝的优点有:
- 更少的用户态与内核态的切换
- 不利用 CPU 计算,减少 CPU 时间
- 零拷贝适合小文件传输
- 如果文件较大,会把数据读入到内核缓冲区,而缓冲区的目的(优点)是循环的获取少量数据
- 一次读入大量数据,不能利用缓冲区的优点
- 如果占用缓冲区内存较大,会影响其他数据对缓冲区的使用
- 如果文件较大,会把数据读入到内核缓冲区,而缓冲区的目的(优点)是循环的获取少量数据
边栏推荐
- Minimum spanning tree based on Kruskal
- Find the maximum value in each tree row [extension of one of the hierarchical traversals]
- Two implementation methods of stack
- [200 opencv routines] 209 Color image segmentation in HSV color space
- Servlet详解
- 嵌入式开发:技巧和窍门——干净地从引导加载程序跳转到应用程序代码
- Graduation design of phase 6 of the construction practice camp
- 磁盘的结构
- Raspberry pie preliminary use
- leetcode_ one thousand three hundred and sixty-five
猜你喜欢
随机推荐
Description of software version selection of kt6368a Bluetooth dual-mode transparent chip
In the first year of L2, arbitrum nitro was upgraded to bring more compatible and efficient development experience
Short video mall system, how does scroll view adapt to the remaining height of the page
树莓派初步使用
旅行商问题(TSP)的相关论文总结
Jianmu continuous integration platform v2.5.0 release
壹沓科技签约七匹狼,助力「中国男装领导者」数字化转型
关于自动控制原理资料更新
Junior college background, 2 years in Suning, 5 years in Ali. How can I get promoted quickly?
Implementation of heap sort and quick sort principle
为什么有的程序员能力一般却能拿到好offer?
After Firefox drag and drop, Baidu search will always be opened by default. If it is a picture, the picture will be opened.
leetcode:515. 在每个树行中找最大值【无脑bfs】
Collapse code using region
Minimum spanning tree based on Kruskal
Learning notes 23-- basic theory of multi-sensor information fusion (Part I)
排查到解决问题的过程:浏览器突然无法访问网页,错误代码:0x80004005,最终定位:“电脑打开热点,电脑就不能上网了”
磁盤的結構
L2 元年,Arbitrum Nitro 升级带来更兼容高效的开发体验
揭秘B站,程序员穿女装敲代码,效率更高是真的吗?









