介绍 Linux 中的零拷贝技术。从 Fuse 学习 中独立出来。
read、write 接口
从普通文件 read,涉及两次复制:
- 从磁盘通过 DMA 读到内核的 page cache
这里的 page cache 机制也是一种 kernel buffer,但专门提供给磁盘文件的。 - 从内核的 page cache 复制到 user buffer
从套接口读数据:
- 从网卡通过 DMA 直接写入 kernel buffer
- 从 kernel buffer 复制到 user buffer
注意,在使用 DMA 之前,磁盘读出来的数据会放到一个寄存器里面,然后通过中断通知 CPU 把数据写到临时的内存中攒批,最后写到 page cache 中。但是该方式性能太差,早已经淘汰了。
读数据过程:
- 调用 read() 函数陷入内核,第一次 context switch
- DMA 控制器将数据从磁盘拷贝到 kernel buffer,这是第一次 DMA 拷贝
- CPU 将数据从 kernel buffer 复制到 user buffer,这是第一次 CPU 拷贝
- CPU 完成拷贝之后,read() 函数返回到用户态,第二次 context switch
写过程类似。
mmap
把 kernel space 的页映射到 user space,所以可以避免从 kernel space 到 user space 的一次复制。
关于 mmap 可以见 内存领域知识。
sendfile
原始 sendfile
sendfile 将数据从磁盘读到内核的 page cache,然后将 page cache 复制到 socket 的 buffer 中。
它的好处是减少了 syscall 的次数。将 read + write 或者 mmap + write 打包了。
但是,仍然需要 2 次 DMA 拷贝和 1 次 CPU 拷贝。
sendfile + DMA 优化
将从 page cache 到 socket buffer 的那一次 CPU 拷贝去掉了。DMA 可以直接从 page cache 拷贝数据到网卡里面。