当前位置: 首页 > news >正文

NIO零拷贝

文章目录

  • 概述
  • 一、socket缓冲区与直接内存
  • 二、零拷贝的实现
    • 2.1、DMA(直接内存访问)
    • 2.2、零拷贝方式一:Linux的MMAP内存映射
    • 2.3、零拷贝方式二:Linux的sendFile
    • 2.4、零拷贝方式三:Linux的slice


本文为个人学习笔记整理,仅供交流参考,非专业教学资料,内容请自行甄别

概述

  在前篇中提到,socket是位于应用层和运输层之间的一个软件抽象层,每次建立连接,都会产生一个socket实例。
  每一个socket中有两个缓冲区,发送缓冲区接收缓冲区。缓冲区数据,只有得到对端确认之后才会清除,并非发送后立刻清除,由此保证消息的可靠传输。


一、socket缓冲区与直接内存

  应用程序要向对端写数据,调用write首先是将应用进程缓冲区的数据,写入到socket的发送缓冲区。操作系统再从socket的发送缓冲区读取数据经过协议栈的处理,发送到对端。
  应用程序缓冲区,通常使用的是直接内存,而非堆内存。如果应用程序缓冲区是堆上分配的,jvm首先会在堆外创建一个direct buffer(直接内存),然后将堆上要发送的数据,拷贝到direct buffer,再写到socket的发送缓冲区。为什么要这样操作?因为堆有垃圾回收机制。一旦触发了垃圾回收,数据位于堆上的位置是有可能发生变化的。(整理,复制算法)如果在write的过程中发生,就会导致错误,即有可能把一个地址传给底层的write,但是这段内存却因为垃圾回收整理内存而失效了。堆外的空间,没有垃圾回收机制,需要手动地进行内存管理。同样带来的问题是,出现内存泄漏的问题,不容易去排查。
  使用direct buffer,在堆外分配一块区域,数据直接放在堆外区域上,然后写到socket的发送缓冲区,节省了将数据从堆复制到direct buffer的IO。

二、零拷贝的实现

  零拷贝指的是,计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域,减少了CPU上下文切换带来的开销。零拷贝只是尽量地去精简拷贝的次数,而非完全无需进行拷贝的操作

2.1、DMA(直接内存访问)

  在早期计算机中,用户进程要读取磁盘上的数据,需要CPU的参与,也就会受到CPU上下文切换开销的影响。而DMA正是用于解决上面提到的问题,它是一种硬件技术,允许外部设备(如硬盘、网卡或声卡)直接与系统内存交换数据,而无需中央处理器(CPU)的干预:使CPU专注于计算任务而非数据传输。
  DMA的核心思想是让DMA控制器直接管理数据在内存和外设之间的传输,CPU只需初始化传输参数,后续操作由DMA控制器自主完成,实际的文件传输经历了以下的过程:

  1. DMA等待数据准备好,把磁盘数据读取到操作系统内核缓冲区。
  2. 用户进程,将内核缓冲区的数据复制到应用程序缓冲区。

在这里插入图片描述
图片来源:图灵学院

  上述的过程,发生了四次上下文切换,四次拷贝
  上下文切换体现在调用send和read方法,每次调用都涉及到用户态->内核态,内核态->用户态的两次切换。
  四次拷贝体现在:

  1. 磁盘数据通过DMA拷贝到文件读取缓冲区。
  2. 文件读取缓冲区数据通过CPU拷贝到应用进程缓冲区。
  3. 应用进程缓冲区数据通过CPU拷贝到发送缓冲区。
  4. 发送缓冲区数据通过DMA拷贝到网络设备缓冲区准备进行发送。

  在上述的过程中,2和3的两次CPU拷贝,实际上是没有必要的,因为在拷贝的过程中,并不需要应用程序对数据进行修改,只是进行了中转。

2.2、零拷贝方式一:Linux的MMAP内存映射

  把磁盘和应用程序缓冲区之间的文件读取缓冲区取消
  磁盘文件分成了很多块,将内存中的区域映射到磁盘对应的区块,通过MMAP的调用,直接将磁盘的区块中的内容,读取到对应的内存区域中,不需要文件读取缓冲区进行中转
在这里插入图片描述
图片来源:图灵学院

2.3、零拷贝方式二:Linux的sendFile

  磁盘->文件读取缓冲区->套接字发送缓冲区->网络设备缓冲区,无需经过应用程序缓冲区的中转。
在这里插入图片描述
图片来源:图灵学院

  如果DMA设备允许,就是两次拷贝:在进行数据传输时,不需要将数据通过cpu进行拷贝,而是告诉cpu数据放在缓冲区内核中的位置和大小。(cpu不拷贝,只传递参数)DMA直接进行读取。

2.4、零拷贝方式三:Linux的slice

  从磁盘读取到内核buffer后,在内核空间直接与socket buffer建立pipe管道。让发送和读取缓冲区共享一个内存区域。(不需要硬件的支持)
在这里插入图片描述

  目前在JAVA的API层面,只支持前两者零拷贝的实现。

http://www.dtcms.com/a/287392.html

相关文章:

  • MySQL的union、union all导致排序失效
  • 低输入电源5.5V/2A同步降压转换器具有多种模式选择
  • roslaunch 文件的核心语法和使用技巧
  • (LeetCode 每日一题) 1233. 删除子文件夹 (排序)
  • TCP/UDP协议深度解析(四):TCP的粘包问题以及异常情况处理
  • 7.19 换根dp | vpp |滑窗
  • 医养照护与管理实训基地建设:创新模式与突破路径
  • 扭蛋机系统开发:打造多元化娱乐生态的新引擎
  • 响应式单位rpx及搭配使用UI产品工具
  • Ambiguity-Resolved Waveform Design for Cell-free OFDM-Based ISAC Systems
  • 【MySQL笔记】视图
  • 力扣 hot100 Day49
  • day25 力扣90.子集II 力扣46.全排列 力扣47.全排列 II
  • 二、环境搭建之CentOS安装Docker
  • GitHub:只支持 Git 作为唯一的版本库格式进行托管
  • 二分查找-69.x的平方根-力扣(LeetCode)
  • 安装单机版本Redis
  • 电商商品综合排序:从需求分析到实时计算的全方位指南
  • 初识Redis---Redis的特性介绍
  • GM-3568JHF vs 普通 RK3568 开发板 — 工业应用对比文案
  • 学习 Python 爬虫需要哪些基础知识?
  • 3516cv610 npu 开发典型功能点的介绍
  • Azure Bicep 是什么?
  • leetcode_121 买卖股票的最佳时期
  • AWS Partner: Accreditation (Technical)
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 57(题目+回答)
  • QT动态加载动态库 QLibrary
  • 从车险理赔到快递签收:打通区块链与现实世界的“最后一公里”——解密预言机(Oracle)
  • aws(学习笔记第四十九课) ECS集中练习(1)
  • 基于深度学习的推荐系统:从协同过滤到神经网络