面试知识库
极高 困难

零拷贝原理#

一句话答案#

零拷贝避免 CPU 参与用户/内核缓冲区间的数据复制,sendfile 省两次拷贝,Kafka/Nginx 用它提升吞吐。

核心要点

传统IO(4次拷贝): 磁盘→内核缓冲→用户缓冲→Socket缓冲→网卡

sendfile(2次): 磁盘→内核缓冲→网卡(CPU不参与拷贝)

mmap(3次): 内核缓冲直接映射到用户空间,省一次拷贝

应用: Kafka(sendfile高吞吐) / RocketMQ(mmap) / Nginx

面试回答(2分钟版)

零拷贝的核心是避免CPU参与用户空间和内核空间之间的数据拷贝。传统IO读文件发网络需要4次拷贝:磁盘到内核PageCache是DMA拷贝,PageCache到用户缓冲区是CPU拷贝,用户缓冲区到Socket缓冲区是CPU拷贝,Socket缓冲区到网卡又是DMA拷贝,还涉及4次用户态和内核态的上下文切换。sendfile系统调用直接在内核空间完成数据传输,数据从PageCache直接到Socket缓冲区再到网卡,完全不经过用户空间,省掉两次CPU拷贝和两次上下文切换。如果网卡支持SG-DMA,还能进一步省掉PageCache到Socket缓冲区的拷贝,只剩两次DMA拷贝。mmap方案则是把内核PageCache映射到用户空间地址,省一次拷贝,适合需要在用户空间修改数据的场景。实际应用中,Kafka消费消息时用sendfile实现高吞吐,RocketMQ的CommitLog用mmap,Nginx发送静态文件也用sendfile。需要注意零拷贝并非零次拷贝,DMA拷贝仍然存在,只是CPU不再参与搬运。

追问与易错

追问方向:

  • “sendfile 和 mmap+write 区别?”→ sendfile 全程在内核完成无需用户空间参与(省两次拷贝),mmap+write 需要用户空间发起 write 调用(省一次拷贝),但 mmap 允许用户空间修改数据
  • “DMA 在零拷贝中的作用?”→ DMA(直接内存访问)让磁盘和网卡直接与内存交换数据不需要 CPU 参与,零拷贝中的两次 DMA 拷贝(磁盘→PageCache、Socket 缓冲→网卡)仍然存在
  • “Java 怎么用零拷贝?”→ FileChannel.transferTo() 底层调用 sendfile,MappedByteBuffer 底层用 mmap;Netty 的 FileRegion 也封装了 transferTo 实现零拷贝

易错点:

  • ❌ 零拷贝就是零次拷贝——仍有 DMA 拷贝
  • ❌ 所有场景都该用零拷贝——需要修改数据时不能用