Zero-copy:数据从磁盘到网卡,能不能不经过用户态拷贝?
TL;DR
Zero-copy 通过减少用户态与内核态之间的数据搬运,降低大文件传输的 CPU 和内存带宽开销,但仍受硬件、加密与数据生命周期约束。
Zero-copy 通过减少用户态与内核态之间的数据搬运,降低大文件传输的 CPU 和内存带宽开销,但仍受硬件、加密与数据生命周期约束。

一次网络传输看起来很简单:从文件读出字节,再写入套接字。但如果数据只是从磁盘搬到网卡,先复制到用户态缓冲区,再复制回内核态,就会产生不必要的 CPU 和内存带宽消耗。Zero-copy(零拷贝)关注的正是如何减少这些中间搬运。
以 Linux 的 sendfile 为例,应用只需告诉内核“把这个文件描述符的内容发送到那个套接字”。内核可以在自己的缓存和网络发送路径之间转移数据,应用不必把每个字节读进自己的缓冲区。对静态文件服务器、代理和大文件分发来说,这能减少用户态与内核态之间的往返。
这里的“零”是工程语境里的零:通常意味着少一次或几次 CPU 参与的数据复制,并不保证物理内存里完全没有任何复制。网卡 DMA、文件系统缓存、加密、压缩、协议封装和硬件能力,都会决定最终路径。某些场景仍需复制,例如数据要被修改、格式转换,或协议栈无法直接引用原始页面。
零拷贝还带来生命周期约束。发送操作尚未完成时,源文件内容不能被随意改写或截断,否则内核可能看到不一致的数据。应用需要处理部分发送、阻塞、错误和背压,不能因为接口看起来是一条直通管道就忽略流量控制。
它的价值不在于追求一个漂亮的术语,而在于把 CPU 从“搬运工”角色中释放出来。是否值得使用,要看数据大小、传输频率、硬件和系统调用路径;小数据、复杂变换或强加密场景未必适合。先画清楚数据从哪里到哪里,再决定删除哪一次复制,通常比盲目追求零拷贝更可靠。
另外,零拷贝并不意味着应用可以忘记背压。发送端必须知道内核何时真正消费了源页面,接收端慢时仍要限制在途数据;否则只是把内存占用从用户态缓冲区转移到内核队列。性能测试也应同时记录 CPU、内存带宽、吞吐和尾延迟,避免只凭系统调用次数得出结论。
资料来源:Linux sendfile(2) 手册



