本文转载自微信公众号「潜行前行」,作者cscw 。转载本文请联系潜行前行公众号。
前言
大白话解释,零拷贝就是没有把数据从一个存储区域拷贝到另一个存储区域。但是没有数据的复制,怎么可能实现数据的传输呢?其实我们在java NIO、netty、kafka遇到的零拷贝,并不是不复制数据,而是减少不必要的数据拷贝次数,从而提升代码性能
零拷贝的好处
缓冲区和虚拟内存
利用第一点特性可以把内核空间地址和用户空间的虚拟地址映射到同一个物理地址,这样DMA就可以填充(读写)对内核和用户空间进程同时可见的缓冲区了;大致如下
传统的 I/O
- #include <unistd>
- ssize_t write(int filedes, void *buf, size_t nbytes);
- ssize_t read(int filedes, void *buf, size_t nbytes);
如java在linux系统上,读取一个磁盘文件,并发送到远程端的服务
「一共有四次用户空间与内核空间的上下文切换。四次数据copy,分别是两次CPU数据复制,两次DMA数据复制」
mmap+write实现的零拷贝
#include
「通过mmap实现的零拷贝I/O进行了4次用户空间与内核空间的上下文切换,以及3次数据拷贝;其中3次数据拷贝中包括了2次DMA拷贝和1次CPU拷贝」
sendfile实现的零拷贝
- #include <sys/sendfile.h>
- ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
「通过sendfile实现的零拷贝I/O使用了2次用户空间与内核空间的上下文切换,以及3次数据的拷贝。其中3次数据拷贝中包括了2次DMA拷贝和1次CPU拷贝」
带有DMA收集拷贝功能的sendfile实现的零拷贝
从Linux 2.4版本开始,操作系统提供scatter和gather的SG-DMA方式,直接从内核空间缓冲区中将数据读取到网卡,无需将内核空间缓冲区的数据再复制一份到socket缓冲区
「带有DMA收集拷贝功能的sendfile实现的I/O使用了2次用户空间与内核空间的上下文切换,以及2次数据的拷贝,而且这2次的数据拷贝都是非CPU拷贝。这样一来我们就实现了最理想的零拷贝I/O传输了,不需要任何一次的CPU拷贝,以及最少的上下文切换」
java提供的零拷贝方式
- public void main(String[] args){
- try {
- FileChannel readChannel = FileChannel.open(Paths.get("./cscw.txt"), StandardOpenOption.READ);
- FileChannel writeChannel = FileChannel.open(Paths.get("./siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
- MappedByteBuffer data = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, 1024 * 1024 * 40);
- //数据传输
- writeChannel.write(data);
- readChannel.close();
- writeChannel.close();
- }catch (Exception e){
- System.out.println(e.getMessage());
- }
- }
- public void main(String[] args) {
- try {
- FileChannel readChannel = FileChannel.open(Paths.get("./cscw.txt"), StandardOpenOption.READ);
- FileChannel writeChannel = FileChannel.open(Paths.get("./siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
- long len = readChannel.size();
- long position = readChannel.position();
- //数据传输
- readChannel.transferTo(position, len, writeChannel);
- //效果和transferTo 一样的
- //writeChannel.transferFrom(readChannel, position, len, );
- readChannel.close();
- writeChannel.close();
- } catch (Exception e) {
- System.out.println(e.getMessage());
- }
- }
欢迎指正文中错误
参考文章
Reference
[1]浅谈 Linux下的零拷贝机制:
https://www.jianshu.com/p/e76e3580e356
[2]面试被问到“零拷贝”!你真的理解吗?:
https://my.oschina.net/u/3990817/blog/3045359
3]java NIO 的通道Channel的理解:
https://blog.csdn.net/qq_27092581/article/details/78347198
[4]Channel基本使用——FileChannel类和内存映射的使用:
https://blog.csdn.net/qq_45337431/article/details/99645809
本文实例为大家分享了微信小程序实现点赞业务的具体代码,供大家参考,具体内容...
复制代码 代码如下: %@LANGUAGE="VBSCRIPT"% % option explicit dim startime,en...
本文实例为大家分享了js实现弹幕效果的具体代码,供大家参考,具体内容如下 效果...
生成HTML方法主要步骤只有两个: 一、获取要生成的html文件的内容 二、将获取的h...
许多网站设计者最常犯的错误便是当其网页能够在IE下正常显示便认为其代码正确无...
有时候我们需要将js的注释去掉,减少代码中的冗余,有时候注释太多导致页面体积...
近日,市场数据调研机构 Netmarketshare 发布了 2020 年 10 月的浏览器市场份额...
学习索引,主要是写出更快的sql,当我们写sql的时候,需要明确的知道sql为什么会...
JSP Spring防止用户重复登录的实现方法 Spring security防用户重复登录 使用spri...
第一个:abbr 或 acronym 这两个标识是一回事,主要是用于一些英语的缩写,当你...