当前位置:网站首页>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 时间
- 零拷贝适合小文件传输
- 如果文件较大,会把数据读入到内核缓冲区,而缓冲区的目的(优点)是循环的获取少量数据
- 一次读入大量数据,不能利用缓冲区的优点
- 如果占用缓冲区内存较大,会影响其他数据对缓冲区的使用
- 如果文件较大,会把数据读入到内核缓冲区,而缓冲区的目的(优点)是循环的获取少量数据
边栏推荐
- Yida technology signed a contract with seven wolves to help the digital transformation of "Chinese men's wear leader"
- ansible基本配置
- Description of software version selection of kt6368a Bluetooth dual-mode transparent chip
- leetcode:55. Jumping game [classic greed]
- 壹沓科技签约七匹狼,助力「中国男装领导者」数字化转型
- St Table + two points
- Embedded development: tips and tricks -- clean jump from boot loader to application code
- The process from troubleshooting to problem solving: the browser suddenly failed to access the web page, error code: 0x80004005, and the final positioning: "when the computer turns on the hotspot, the
- 如何比较两个或多个分布:从可视化到统计检验的方法总结
- Shutter precautions for using typedef
猜你喜欢
随机推荐
系统测试主要步骤
[untitled]
TCP RTT测量妙计
Double linked list implementation
Development trend and path of SaaS industry in China
Flutter 如何使用在线转码工具将 JSON 转为 Model
Cannot find reference 'imread' in 'appears in pycharm__ init__. py‘
EasyBypass
短视频商城系统,scroll-view如何自适应页面剩余高度
Resolving the conflict problem of the flutter Library
Reduce the pip to the specified version (upgrade the PIP through pycharm, and then reduce it to the original version)
KT6368A蓝牙双模透传芯片软件版本选型说明
如何抓手机的包进行分析,Fiddler神器或许能帮到您!
What aspects should we start with in the feasibility analysis of dry goods?
The profound meaning of unlimited ecological development in Poka -- Multidimensional Interpretation of parallel chain
Interviewer: you said you are proficient in redis. Have you seen the persistent configuration?
直播软件app开发,左右自动滑动的轮播图广告
解决dataframe报错ValueError: Cannot take a larger sample than population when ‘replace=False‘
How does flutter use the online transcoding tool to convert JSON to model
[notes of Wu Enda] multivariable linear regression









