详细说明零拷贝

详细说明零拷贝

  • 【一】零拷贝介绍
    • 【1】说明
    • 【2】为什么需要零拷贝?—— 传统数据传输的问题
    • 【3】零拷贝的核心优化
    • 【4】零拷贝的实现方式
      • (1)mmap(内存映射)
      • (2)sendfile(Linux 系统调用)
      • (3)其他零拷贝实现
    • 【5】零拷贝的核心价值
  • 【二】NIO的零拷贝MappedByteBuffer(内存映射文件)
  • 【三】Kafka的零拷贝
  • 【四】Nginx的零拷贝

【一】零拷贝介绍

【1】说明

零拷贝(Zero-Copy)是一种减少数据在内存中不必要复制的技术,核心目标是在数据传输(如文件读写、网络发送)过程中,避免 CPU 参与冗余的数据拷贝操作,从而提升性能(减少 CPU 占用、降低内存带宽消耗、减少用户态与内核态切换开销)。

【2】为什么需要零拷贝?—— 传统数据传输的问题

在传统数据传输流程中(例如 “从磁盘文件读取数据并通过网络发送”),数据需要经过多次拷贝和状态切换,效率极低。以下是具体流程:

传统流程(以 “读取文件并发送到网络” 为例):
(1)第一次拷贝(DMA 拷贝):CPU 发起 DMA(直接内存访问)请求,磁盘控制器将数据从磁盘读取到内核缓冲区(内核态内存),此过程不占用 CPU。
(2)第二次拷贝(CPU 拷贝):数据从内核缓冲区拷贝到用户缓冲区(用户态内存),此时 CPU 参与拷贝,用户进程可访问数据。
(3)第三次拷贝(CPU 拷贝):用户进程将数据从用户缓冲区拷贝到Socket 缓冲区(内核态中为网络传输准备的缓冲区),CPU 再次参与。
(4)第四次拷贝(DMA 拷贝):DMA 将 Socket 缓冲区的数据发送到网络接口(如网卡),不占用 CPU。

额外开销:
(1)用户态与内核态切换:步骤 1→2(内核态→用户态)、步骤 2→3(用户态→内核态),每次切换需保存 / 恢复寄存器、刷新 TLB 等,开销较大。
(2)CPU 冗余拷贝:步骤 2 和步骤 3 的拷贝由 CPU 执行,会占用 CPU 资源,尤其在大文件或高并发场景下,会成为性能瓶颈。

【3】零拷贝的核心优化

零拷贝并非 “完全不拷贝”(数据最终仍需从源设备到目标设备),而是减少 CPU 参与的拷贝次数(保留必要的 DMA 拷贝,因 DMA 不占用 CPU),并减少用户态与内核态的切换。

【4】零拷贝的实现方式

不同操作系统(如 Linux、Windows)提供了多种零拷贝机制,以下是最常用的几种:

(1)mmap(内存映射)

原理:将内核缓冲区与用户缓冲区映射到同一块物理内存,使用户进程可直接访问内核缓冲区,避免 “内核缓冲区→用户缓冲区” 的 CPU 拷贝。

流程(以 “读文件并发送网络” 为例):
(1)磁盘数据通过 DMA 拷贝到内核缓冲区。
(2)调用mmap()将内核缓冲区与用户进程的虚拟地址空间映射(无数据拷贝,仅建立地址映射关系)。
(3)用户进程直接操作 “映射后的内存”(本质是内核缓冲区),无需拷贝到用户缓冲区。
(4)数据从内核缓冲区拷贝到 Socket 缓冲区(CPU 拷贝),再通过 DMA 发送到网络。

优势:
(1)减少 1 次 CPU 拷贝(省去 “内核→用户” 的拷贝)。
(2)用户态与内核态切换次数从 2 次减少到 1 次(仅mmap()和write()各 1 次切换)。

缺点:
(1)仍存在 “内核缓冲区→Socket 缓冲区” 的 CPU 拷贝。
(2)若映射的文件被修改,可能导致用户进程崩溃(需谨慎处理)。

应用:
(1)大文件读写(如数据库表文件映射)。
(2)Kafka 的日志文件读写(通过 mmap 将磁盘文件映射到内存,提升读写效率)。

(2)sendfile(Linux 系统调用)

原理:直接在内核空间完成数据从文件到网络的传输,完全避免用户态参与,减少 CPU 拷贝和状态切换。

流程(以 “读文件并发送网络” 为例):
(1)磁盘数据通过 DMA 拷贝到内核缓冲区。
(2)调用sendfile()系统调用,内核直接将数据从内核缓冲区拷贝到 Socket 缓冲区(早期为 CPU 拷贝)。
(3)DMA 将 Socket 缓冲区数据发送到网络。

优化(Linux 2.4+):
引入DMA scatter-gather(分散 - 聚集) 技术:内核无需将数据拷贝到 Socket 缓冲区,而是直接告诉网卡 “数据在内核缓冲区的位置和长度”,网卡通过 DMA 直接从内核缓冲区读取数据并发送到网络。此时流程简化为:
(1)磁盘→内核缓冲区(DMA 拷贝)。
(2)内核缓冲区→网络(DMA scatter-gather,无 CPU 拷贝)。

优势:
(1)完全避免用户态与内核态切换(仅 1 次sendfile()调用)。
(2)无 CPU 拷贝(仅 2 次 DMA 拷贝),效率极高。

缺点:
(1)仅适用于 “文件→网络” 的单向传输(无法在用户态处理数据)。

应用:
(1)Web 服务器(Nginx 默认启用sendfile模块,加速静态文件传输)。
(2)视频点播、大文件下载等场景。

(3)其他零拷贝实现

(1)Windows:TransmitFile:功能类似sendfile,用于文件到网络的零拷贝传输。
(2)Java NIO:FileChannel.transferTo()/transferFrom():底层调用操作系统的零拷贝接口(如 Linux 的sendfile、Windows 的TransmitFile),实现文件通道与其他通道(如 SocketChannel)的直接数据传输。

传输方式 数据拷贝次数(CPU) 数据拷贝次数(DMA) 用户态↔内核态切换次数 适用场景
传统(read+write) 2 次(内核→用户、用户→Socket) 2 次(磁盘→内核、Socket→网络) 4 次(read 进入内核、返回用户;write 进入内核、返回用户) 需用户态处理数据的场景
mmap+write 1 次(内核→Socket) 2 次 2 次(mmap、write 各 1 次) 需用户态处理数据,且数据量大
sendfile(优化后) 0 次 2 次 1 次(仅 sendfile 调用) 纯文件→网络传输(无需用户处理)

【5】零拷贝的核心价值

(1)减少 CPU 占用:避免冗余的 CPU 拷贝,释放 CPU 资源用于其他任务。
(2)降低内存带宽消耗:减少数据在内存中的重复存储,节省内存带宽。
(3)减少状态切换:用户态与内核态切换开销大,零拷贝可大幅减少切换次数。

这些优势在高并发、大文件传输场景(如视频流服务、日志收集、消息中间件)中尤为重要,能显著提升系统吞吐量。

【二】NIO的零拷贝MappedByteBuffer(内存映射文件)

通过内存映射将文件直接映射到用户进程的地址空间,操作内存即可等同于操作文件,避免了传统 IO 的read()/write()拷贝。
应用场景:
(1)大文件的随机读写(如数据库索引文件、日志文件)。
(2)需要频繁访问文件内容的场景(如解析大型 CSV/XML)。

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;public class MappedFileExample {public static void main(String[] args) throws Exception {try (RandomAccessFile file = new RandomAccessFile("data.txt", "rw");FileChannel channel = file.getChannel()) {// 映射文件的前1024字节到内存(读写模式)MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE,  // 模式:读写0,  // 起始位置1024  // 映射长度);// 直接操作内存(等同于操作文件)buffer.put("Hello Zero-Copy".getBytes());// 无需显式flush,内核会自动同步到磁盘(可通过force()强制同步)buffer.force();}}
}

文件数据通过内存映射被 “映射” 到用户空间的虚拟内存,用户操作MappedByteBuffer时,由操作系统负责数据与磁盘的同步(通过页缓存机制),避免了用户空间与内核空间的拷贝。

【三】Kafka的零拷贝

Kafka 作为高吞吐量的消息队列,其高性能的核心原因之一就是大量使用零拷贝:
(1)生产者写入数据时,数据先写入页缓存(内核空间),避免用户空间拷贝。
(2)消费者读取数据时,通过sendfile()将页缓存中的数据直接发送到网络套接字,全程无用户空间与内核空间的拷贝。
(3)数据持久化到磁盘时,利用操作系统的页缓存同步机制,减少物理 IO 次数。

【四】Nginx的零拷贝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91204.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91204.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker部署自己写的c++http服务器教程

我用的是ubuntu 22.04环境下 qt c 写的应用程序,是终端程序,不是界面,然后用linuxdeployqt工具将其打包成了AppImage可执行文件,以上是部署前的准备工作,需要确保AppImage可执行文件在自己的ubuntu上可以运行才能执行以…

Caffeine 缓存库的常用功能使用介绍

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…

C# _列表(List<T>)_ 字典(Dictionary<TKey, TValue>)

目录 列表(List)特点 创建列表 RemoveAll 删除与之条件相匹配的数据 会返回删除的个数 Capacity 获取或设置列表的容量 更多方法可参照上篇文章:C#_ArrayList动态数组 字典(Dictionary)特点 定义一个字典 向字…

【实时Linux实战系列】实时网络控制与调度

在实时控制系统中,网络调度是确保实时数据流传输和处理不受延迟影响的关键。实时网络控制与调度技术对于工业自动化、金融交易、多媒体流等领域至关重要。通过合理设计网络调度策略,可以显著提高系统的实时性和可靠性。本文将介绍如何在实时控制系统中实…

Qwen3-Coder:介绍及使用 -- 超强AI编程助手

更多内容:XiaoJ的知识星球 目录一、Qwen3-Coder模型介绍1.预训练阶段(Pre-Training)2.后训练阶段(Post-Training)1)Scaling Code RL: Hard to Solve, Easy to Verify2)Scaling Long-Horizon RL二…

uniapp 如果进入页面输入框自动聚焦,此时快速返回页面或者跳转到下一个页面,输入法顶上来的页面出现半屏的黑屏问题。

如果进入页面输入框自动聚焦,此时快速返回页面或者跳转到下一个页面,输入法顶上来的页面出现半屏的黑屏问题。输入法出来后,设置了自动将页面顶上来的配置:pages.json"softinputMode": "adjustResize""g…

深入了解 Kubernetes(k8s):从概念到实践

目录 一、k8s 核心概念 二、k8s 的优势 三、k8s 架构组件 控制平面组件 节点组件 四、k8s docker 运行前后端分离项目的例子 1. 准备前端项目 2. 准备后端项目 3. 创建 k8s 部署配置文件 4. 部署应用到 k8s 集群 在当今云计算和容器化技术飞速发展的时代&#xff0c…

Android User版本默认用test-keys,如何改用release-keys

Android User版本 默认用test-keys, 如何改用release-keys 开发云 - 一站式云服务平台 --- build/core/Makefile | 5 1 file changed, 5 insertions() diff --git a/build/core/Makefile b/build/core/Makefile index --- a/build/core/Makefile b/build/core…

从零开始学习Dify-数据库数据可视化(五)

概述上一篇文章我们围绕 Excel 文件展开数据可视化教学,逐步掌握了数据导入、图表构建和 AI 智能分析。在实际业务环境中,很多数据并不是保存在表格中,而是存储于数据库系统中,尤其是最常见的 MySQL。本篇作为本系列的第五篇&…

使用vue2和 element-ui 做一个点餐收银台系统前端静态项目

今天给大家分享一个 关于点餐收银台的静态网站,最近一直在练习前端项目,就使用vue2和 element-ui 做了一个 这样简单的 收银台系统。先给大家看一下 做出来的样子。 因为是练习项目 所以页面功能还是比较简单的。 使用的技术是: 技术栈 Vu…

Spring Boot自动配置原理深度解析

Spring Boot自动配置原理深度解析 一、自动配置核心概念 1.1 什么是自动配置 Spring Boot自动配置(Auto-Configuration)是其核心特性之一,能够根据项目依赖自动配置Spring应用程序。例如: 当检测到H2数据库依赖时,自动配置内存数据库当存在Sp…

关于 Apache Ignite 中 Job 调度(Job Scheduling)与冲突控制(Collision Control) 的机制说明

这段内容是关于 Apache Ignite 中 Job 调度(Job Scheduling)与冲突控制(Collision Control) 的机制说明。我来为你逐段解析,帮助你深入理解其原理和使用方式。🔍 一、核心概念:Job 调度与 Colli…

网络资源模板--基于Android Studio 实现的课程管理App

目录 一、测试环境说明 二、项目简介 三、项目演示 四、部设计详情(部分) 登录页 首页 五、项目源码 一、测试环境说明 电脑环境 Windows 11 编写语言 JAVA 开发软件 Android Studio (2020) 开发软件只要大于等于测试版本即可(近几年官网直接下载也可…

ROUGE-WE:词向量化革新的文本生成评估框架

一、ROUGE 基础与核心局限 ROUGE(Recall-Oriented Understudy for Gisting Evaluation) 是自动文本摘要与机器翻译的主流评估指标,由 Chin-Yew Lin 在2004年发表的论文中首次系统提出。其核心变体包括: ROUGE-N:基于…

MGER综合实验

一.拓扑二、实验需求 1、R5为ISP,只能进行IP地址配置,其所有地址均配为公有IP地址; 2、R1和R5间使用PPP的PAP认证,R5为主认证方; R2与R5之间使用ppp的CHAP认证,R5为主认证方; R3与R5之间使用HDLC封装; 3、R1、R2、R3构建一个MGRE环…

高可用集群Keepalived、Redis、NoSQL数据库Redis基础管理

1. 总结负载均衡常见的算法 轮询 (Round Robin):按顺序将请求依次分配给后端服务器,适合服务器性能相近的场景。 加权轮询 (Weighted Round Robin):在轮询的基础上,根据服务器的权重分配请求。 随机 (Random):随机选…

【深度学习】独热编码(One-Hot Encoding)

独热编码(One-Hot Encoding) 在机器学习中,数据预处理是不可或缺的关键一步。面对各种非数值类型的分类数据(Categorical Data),如何将其转换为机器学习模型能够“理解”的语言呢?独热编码&…

Promise完全体总结

我们在上篇文章提到了异步会导致无法通过返回值来获取函数的执行结果,我们通过传入一个回调函数的方式,以参数的形式获取到了我们想要获取的数据,但是这样如果需要对数据进行多次操作导致形成回调地狱那种不便于阅读以及护理的代码。为了解决…

SpringJDBC源码初探-DataSource类

一、DataSource接口核心作用 DataSource是JDBC规范的核心接口,位于javax.sql包中,用于替代传统的DriverManager获取数据库连接。Spring框架通过org.springframework.jdbc.datasource包对该接口进行了增强,提供连接池管理、事务绑定等高级特性…

C语言(08)——关于指针(逐渐清晰版)

为了更好地理解本篇文章的知识内容,读者可以将以下文章作为补充知识进行阅读 : C语言————原码 补码 反码 (超绝详细解释)-CSDN博客 C语言————二、八、十、十六进制的相互转换-CSDN博客 C语言————斐波那契数列的理解…