文章目录

  • 一、 零拷贝 简介
  • 二、 传统 BIO 数据拷贝分析 ( 4拷贝 4切换 )
  • 三、 mmap 内存映射 ( 3拷贝 4切换 )
  • 四、 sendFile 函数 ( Linux 2.1 优化 ) ( 3拷贝2切换 )
  • 五、 sendFile 函数 ( Linux 2.4 优化 ) ( 2拷贝 2切换 )

一、 零拷贝 简介


零拷贝作用 : 在网络编程中 , 如果要进行性能优化 , 肯定要涉及到零拷贝 , 使用零拷贝能极大的提升数据传输性能 ;

零拷贝类型 : mmap ( 内存映射 ) 和 sendFile;

数据角度分析 : 在零拷贝机制中 , 整个数据在内存中只有一份数据 , 非零拷贝机制中 , 内核缓冲区 , 用户缓冲区 , Socket 缓冲区 , 各有一份数据 ;

零拷贝指的是没有 CPU 拷贝 , 都是 DMA ( 直接内存访问 ) 拷贝 ;

零拷贝性能优势 : 没有复制数据带来的内存开销 , 没有 CPU 拷贝 , 直接节省了大量 CPU 计算资源 ;

二、 传统 BIO 数据拷贝分析 ( 4拷贝 4切换 )


传统 BIO 数据拷贝代码示例 :

package kim.hsl.nio.zerocopy;import java.io.FileInputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;public class BIOClientDemo {public static void main(String[] args) {try {// 客户端与服务器端连接过程忽略, 主要是分析数据拷贝过程Socket socket = new Socket();InetSocketAddress inetSocketAddress =new InetSocketAddress(Inet4Address.getLocalHost(), 8888);socket.connect(inetSocketAddress);// 分析下面过程中, 数据拷贝次数, 和用户态与内核态的转换次数// 1. 从文件中读取数据FileInputStream fileInputStream = new FileInputStream("file.txt");byte[] buffer = new byte[1024];// 首先将硬盘中的文件, 进行 DMA 拷贝, 此处对应 read 方法, // 将文件数据从硬盘中拷贝到 内核缓冲区  ( 用户态切换成内核态 )// 将内核缓冲区中的数据, 通过 CPU 拷贝 方式, 拷贝到 用户缓冲区  ( 内核态切换成用户态 )int readLen = fileInputStream.read(buffer);// 2. 写出数据到服务器// 将用户缓冲区中的数据, 再次通过 CPU 拷贝方式, 拷贝到 Socket 缓冲区 ( 用户态切换成内核态 )// 再次使用 DMA 拷贝, 将 Socket 缓冲区中的数据拷贝到 协议栈 ( Protocol Engine ) 中socket.getOutputStream().write(buffer, 0, readLen);} catch (IOException e) {e.printStackTrace();}}
}

分析上述代码中数据拷贝次数 , 用户态与内核态状态切换 ;

1 . fileInputStream.read(buffer) 操作数据拷贝及状态转换分析 :

① 硬盘 ( 初始用户态 ) -> 内核缓冲区 ( 内核态 ) : 首先将硬盘中的文件 , 进行 DMA[1]^{[1]}[1] 拷贝 , 此处对应 read 方法 , 将文件数据从硬盘中拷贝到 内核缓冲区 ; ( 用户态切换成内核态 )

② 内核缓冲区 ( 内核态 ) -> 用户缓冲区 ( 用户态 ) : 将内核缓冲区中的数据 , 通过 CPU 拷贝 方式 , 拷贝到 用户缓冲区 ; ( 内核态切换成用户态 )

2 . socket.getOutputStream().write(buffer, 0, readLen) 操作数据拷贝及状态转换分析 :

① 用户缓冲区 ( 用户态 ) -> Socket 缓冲区 ( 内核态 ) : 将用户缓冲区中的数据 , 再次通过 CPU 拷贝 方式 , 拷贝到 Socket 缓冲区 ; ( 用户态切换成内核态 )

② Socket 缓冲区 ( 内核态 ) -> 协议栈 : 再次使用 DMA[1]^{[1]}[1] 拷贝 , 将 Socket 缓冲区中的数据拷贝到 协议栈 ( Protocol Engine ) 中 ;

3 . 总结 : 上述进行了 444 次拷贝 , 333 次用户态与内核态之间的状态切换 , 代价很高 ;

① 拷贝次数分析 : 开始时数据存储在 硬盘文件 中 , 直接内存拷贝 ( Direct Memory Access ) 到 内核缓冲区 , CPU 拷贝 到 用户缓冲区 , CPU 拷贝 到 Socket 缓冲区 , 直接内存拷贝 ( Direct Memory Access ) 到 协议栈 ;

硬盘文件 -> 内核缓冲区 ( 内核空间 ) -> 用户缓冲区 ( 用户空间 ) -> Socket 缓冲区 ( 内核空间 ) -> 协议栈

② 状态改变分析 : 开始运行的是用户应用程序 , 起始状态肯定是用户态 , 之后将硬盘文件数据拷贝到内核缓冲区后 , 转为内核态 , 之后又拷贝到了用户缓冲区 , 转为用户态 ; 数据写出到 Socket 缓冲区 , 又转为内核态 , 最后再切换成用户态 , 执行后续应用程序代码逻辑 ;

用户态 -> 内核态 -> 用户态 -> 内核态 -> 用户态

[1][1][1] DMA 全称 ( Direct Memory Access ) , 直接内存拷贝 , 该拷贝通过内存完成 , 不涉及 CPU 参与 ;

三、 mmap 内存映射 ( 3拷贝 4切换 )


将硬盘中的文件映射到 内核缓冲区 , 用户空间中的应用程序也可以访问该 内核缓冲区 中的数据 , 使用这种机制 , 原来的 444 次数据拷贝减少到了 333 次 ,

1 . mmap 数据拷贝过程 :

① 硬盘文件 -> 内核缓冲区 : 硬盘文件数据 , DMA 拷贝到 内核缓冲区 中 , 应用程序可以直接访问该 内核缓冲区中的数据 ;

② 内核缓冲区 -> Socket 缓冲区 : 内核缓冲区 数据 , 通过 CPU 拷贝到 Socket 缓冲区 ;

③ Socket 缓冲区 -> 协议栈 : Socket 缓冲区 数据 , 通过 DMA 拷贝到 协议栈 ;

硬盘文件 -> 内核缓冲区 ( 内核空间 ) -> Socket 缓冲区 ( 内核空间 ) -> 协议栈

2 . mmap 状态切换 : 其状态切换还是 333 次 , 由初始状态 用户态 , 在拷贝数据到内核缓冲区时 , 切换成内核态 , 访问该内核缓冲区数据时 , 又切换成用户态 , 将数据拷贝到 Socket 缓冲区时 , 切换成内核态 , 最后再切换成用户态 , 执行后续应用程序代码逻辑 ;

用户态 -> 内核态 -> 用户态 -> 内核态 -> 用户态

四、 sendFile 函数 ( Linux 2.1 优化 ) ( 3拷贝2切换 )


sendFile 是 Linux 提供的函数 , 其实现了由 内核缓冲区 直接将数据拷贝到 Socket 缓冲区 , 该操作直接在内核空间完成 , 不经过用户空间 , 没有用户态参与 , 因此 减少了一次用户态切换 ;

此次优化 , 由原来的 444 次拷贝 , 333 次状态切换 , 变成 333 次拷贝 , 222 次状态切换 ;

1 . sendFile 函数 数据拷贝分析 :

① 硬盘文件 -> 内核缓冲区 : 硬盘文件数据 , DMA 拷贝到 内核缓冲区 中 ;

② 内核缓冲区 -> Socket 缓冲区 : 内核缓冲区 数据 , 通过 CPU 拷贝到 Socket 缓冲区 ;

③ Socket 缓冲区 -> 协议栈 : Socket 缓冲区 数据 , 通过 DMA 拷贝到 协议栈 ;

硬盘文件 -> 内核缓冲区 ( 内核空间 ) -> Socket 缓冲区 ( 内核空间 ) -> 协议栈

2 . sendFile 函数 状态切换分析 : 其状态切换只有 222 次 , 由初始状态 用户态 , 在拷贝数据到内核缓冲区时 , 切换成内核态 , 在内核态直接将数据拷贝到 Socket 缓冲区时 , 还是处于内核状态 , 之后拷贝到协议栈时 , 变成用户状态 ;

用户态 -> 内核态 -> 用户态

五、 sendFile 函数 ( Linux 2.4 优化 ) ( 2拷贝 2切换 )


sendFile 是 Linux 提供的函数 , 其在 Linux 2.4 版本中 , 直接将数据从 内核缓冲区 拷贝到 协议栈 中 ;

此次优化 , 由原来的 444 次拷贝 , 333 次状态切换 , 变成 222 次拷贝 , 222 次状态切换 ;

1 . sendFile 函数 数据拷贝分析 : 全称 DMA 拷贝 , 没有 CPU 拷贝 ;

① 硬盘文件 -> 内核缓冲区 : 硬盘文件数据 , DMA 拷贝到 内核缓冲区 中 ;

② 内核缓冲区 -> -> 协议栈 : 通过 DMA 拷贝 , 将 内核缓冲区 中的数据直接拷贝到 协议栈 ;

硬盘文件 -> 内核缓冲区 ( 内核空间 ) -> 协议栈

2 . sendFile 函数 状态切换分析 : 其状态切换只有 222 次 , 由初始状态 用户态 , 在拷贝数据到内核缓冲区时 , 切换成内核态 , 在内核态直接将数据拷贝到协议栈时 , 变成用户状态 ;

用户态 -> 内核态 -> 用户态

3 . 少量 CPU 拷贝 : 该机制还存在少量的 CPU 拷贝 , 其 对性能的消耗忽略不计 ; 这些 CPU 拷贝操作是从 内核缓冲区 中将数据的长度 ( Length ) , 偏移量 ( Offset ) 拷贝到 Socket 缓冲区 ;

【Netty】mmap 和 sendFile 零拷贝原理相关推荐

  1. 7 张图,轻松掌握零拷贝原理

    零拷贝是老生常谈的问题啦,大厂非常喜欢问.比如Kafka为什么快,RocketMQ为什么快等,都涉及到零拷贝知识点.最近技术讨论群几个伙伴分享了阿里.虾皮的面试真题,也都涉及到零拷贝.因此本文将跟大家 ...

  2. 【Netty】Netty零拷贝原理

    前言 理解零拷贝 零拷贝是Netty的重要特性之一,而究竟什么是零拷贝呢? WIKI中对其有如下定义: "Zero-copy" describes computer operati ...

  3. java transferto_小六六学Netty系列之Java 零拷贝

    前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger种一棵树最好的时间是十年前,其次是现在 我知道很多人不玩qq了 ...

  4. 【netty学习】之零拷贝

    零拷贝 1.零拷贝是从操作系统的角度出发,因为内核缓冲区之间没有数据是重复的,只有kernel buffer一份数据 2.零拷贝不仅仅带来更少的数据复制,还能带来其他性能的优势,例如更少的上下文切换, ...

  5. Netty中ByteBuf 的零拷贝

    转载:https://www.jianshu.com/p/1d1fa2fe1ed9 此文章已同步发布在我的 segmentfault 专栏. 根据 Wiki 对 Zero-copy 的定义: &quo ...

  6. Linux网络编程--sendfile零拷贝高效率发送文件

    本博文介绍使用sendfile函数进行零拷贝发送文件,实现高效数据传输,并对其进行验证. 那么什么是sendfile呢? linux系统使用man sendfile,查看sendfile原型如下: # ...

  7. Kafka速度快的原因-sendfile零拷贝介绍

    所谓的零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手.零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换.对 Linux 操作系统而言,零拷贝技术依赖于底层 ...

  8. Netty工作笔记0030---NIO与零拷贝原理剖析

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 看看传统的IO,copy文件需要读取和写入 传统的IO,从底层来看是怎么样的呢 这里左侧是用户态, ...

  9. Netty工作笔记0031---NIO零拷贝应用案例

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152. 传统IO的服务器端,这里从客户端接收到数据以后,不再进行写入文件操作了. 读取本地文件,然后发送 ...

最新文章

  1. 分布式事务不理解?一次给你讲清楚!
  2. 重庆邮电大学发布2021年最新小样本目标检测综述
  3. oracle jdedward,Oracle JDEdwards EnterpriseOne Tools任意文件上传漏洞(CVE-2011-2317)
  4. 如何为SQL Server2008添加登录账户并配置权限
  5. linux 永久修改 igmp 版本,Linux环境变量的修改(永久,暂时)
  6. 计算机基础课在护理专业中的应用,计算机基础教育在护理教育中的应用论文.doc...
  7. 编程之美2.2 不要被阶乘吓到
  8. Zabbix监控MySQL工具
  9. matlab里面的取整函数
  10. 一个好用的hibernate泛型dao
  11. 2020年计算机设计大赛 人流量预测 (国赛三等奖)
  12. android 史上最简单behavior,安卓behavior详解1--系统behavior的简单应用
  13. Java之美[从菜鸟到高手演变]之Java学习方法
  14. 浅学 web安全知识(好奇)
  15. 机械硬盘启动失败,总是转一下挺停一下
  16. i.MX6ULL驱动开发 | 04-Linux设备树基本语法与实例解析
  17. 用Python量化海龟交易法则
  18. 宏颜获水: 百度ceo 李彦宏惨槽泼水,懵了!
  19. 外汇天眼:外汇中的做空和做多是什么意思?有什么区别?
  20. Nature Metabolism I 衰老的单细胞组学研究进展及展望

热门文章

  1. 面向 Photoshop 的英特尔® Texture Works 插件
  2. TCP和UDP和IP和HTTP和socket
  3. Bootstrap File Input 真正 解决跨域问题
  4. 信息网络基础设施普遍薄弱,提防信息安全风险--央行副行长
  5. 理解 Delphi 的类(十一) - 深入类中的方法[8] - 抽象方法与抽象类
  6. 自己做的几个小软件(数学工具和游戏),用C/C#制作,用到许多相关的C#技术细节,可以免费提供下载,感兴趣的,来看一下...
  7. 【FJOI2015】最小覆盖双圆问题
  8. css中那些容易被我们程序猿所忽略的选择器
  9. 【bzoj3224】 Tyvj1728—普通平衡树
  10. PHP垃圾回收机制防止内存溢出