A11 — The Memory Boundary Between User and Kernel: Zero-Copy Technology

Key Insight: The fastest path from disk to network is to not copy at all.


Memory Boundary Between User Mode and Kernel Mode

User programs and the kernel have separate address spaces. Interaction requires system calls or specific mechanisms.

Bash
用户态和内核态的隔离:

用户地址空间(0x00000000 ~ 0x7FFFFFFFFFFF):
  - 每个进程有独立的页表
  - 只能访问自己的虚拟地址
  - 访问内核地址 → 崩溃

内核地址空间(0xFFFF800000000000 ~):
  - 所有进程共享
  - 内核可以访问任何物理内存
  - 用户态不能直接访问

数据交互的方式:

1. 系统调用参数传递(少量数据):
   read(fd, buf, 1024);  // buf 在用户态,内核写进去

2. mmap(大量数据):
   mmap(NULL, size, PROT, MAP_SHARED, fd, 0);
   // 用户态直接访问文件内容,内核参与 page fault

3. 共享内存(进程间):
   shm_open() / mmap(MAP_SHARED)
   // 用户态和内核共享同一块物理页

Data Copy Path in Traditional I/O

Bash
传统 read/write 的数据路径:

读取文件到 socket(传统方式):

  [磁盘]                    [Page Cache]                    [用户 Buffer]                    [Socket Buffer]                    [网络]
    │                            │                             │                                │                            │
    ▼                            ▼                             ▼                                ▼                            ▼
  DMA ──────────────→ 物理页(Page Cache) ◄──── 内核读文件    │                                │                            │
                                                              │                                │                            │
                                                           copy ──────────────────────────► │                                │
                                                                                             │                                │
                                                           copy ◄──────────────────────────── │                                │
                                                                                                                    copy ────────────► │
                                                                                                                        │                            │
                                                                                                                         ▼                            ▼
                                                                                                                    socket buffer                DMA
                                                                                                                    to network

复制次数:
  1. 磁盘 → Page Cache(DMA)
  2. Page Cache → 用户 Buffer(memcpy)
  3. 用户 Buffer → Socket Buffer(memcpy)
  → 4 次 DMA/memcpy

用户态参与:
  → CPU 执行 memcpy
  → 用户态和内核态切换(syscall)
  → 高延迟,高 CPU 占用

Zero-Copy Technology

The goal of zero-copy is to reduce or eliminate data copying between user mode and kernel mode.

Bash
sendfile() 系统调用:

#include <sys/sendfile.h>
ssize_t sendfile(out_fd, in_fd, &offset, count);

数据路径:

  [磁盘] → [Page Cache] → [Socket Buffer] → [网络]
              │               │
              │               │
           DMA ──────────► │
                            │
                            copy(Page Cache → Socket Buffer)
                            // 仍然有 1 次 copy

适合场景:
  - 文件到 socket 的传输(静态文件服务)
  - 不需要处理数据,直接转发

splice() 系统调用:

splice(fd_in, &off_in, fd_out, &off_out, len, flags);

  - 在两个文件描述符之间移动数据
  - 不经过用户态
  - 内部使用管道缓冲区作为中转

数据路径:
  [磁盘] → [Page Cache] → [pipe] → [Socket Buffer] → [网络]
              │              │               │
              │              │               │
           DMA              zero-copy       copy(pipe → socket)
                            // 内核内部移动,不需要用户态

Bash
mmap + write(内存映射文件):

1. mmap 把文件映射到用户地址空间
2. write 把数据写入 socket
3. 内核自动把 Page Cache 的数据发送到网络

改进点:
  - 减少一次 User Buffer 的 memcpy
  - 但仍然需要 Page Cache → Socket Buffer copy

data sync:
  msync() / fsync() 确保数据写回磁盘(不用于零拷贝)

零拷贝的完整实现(真正的零 copy):
  - 需要硬件支持:RDMA(Remote Direct Memory Access)
  - 或者:网卡支持 scatter-gather DMA
  - 数据直接从 Page Cache → 网卡,不需要中间 copy

DMA and Zero-Copy

Bash
传统 DMA vs RDMA:

传统 DMA:
  - 数据必须经过物理内存
  - CPU 参与设置 DMA 描述符
  - 系统调用有开销

RDMA(Remote Direct Memory Access):
  - 网卡直接读写远程内存
  - 零拷贝:网卡 → 远程内存
  - 无 CPU 参与,无系统调用开销
  - 适用:高性能计算、机器学习、存储

InfiniBand / RoCE / iWARP:
  - RDMA 的网络实现
  - 数据传输绕过内核
  - 延迟 < 1μs(vs TCP 10~100μs)

Bash
网卡 scatter-gather:

支持 SG 的网卡可以直接从多个内存区域读取数据:

  skb(socket buffer)包含多个物理地址:
    - iovec[0]: page 0, offset 0, len 1500
    - iovec[1]: page 1, offset 0, len 1500
  → 网卡直接从这两个页 DMA 数据

Linux 的实现:
  - skb(socket buffer)管理数据
  - page pool:零拷贝的页面管理
  - XDP(Express Data Path):跳过协议栈,直接网卡处理

Summary

  • User/Kernel Isolation: Userspace has independent page tables; kernel has global access; requires system calls for interaction
  • Traditional I/O: Disk → Page Cache → User Buffer → Socket Buffer; 4 copies; CPU involved
  • sendfile(): Page Cache to Socket Buffer; 2 copies (suitable for file-to-socket)
  • splice(): Transfers via pipe; kernel-internal zero-copy; no userspace involvement
  • RDMA: NIC directly reads/writes remote memory; fully zero-copy; requires special hardware

Next (A12): Last A-layer article. Memory flow across all layers: physical memory → page table → buddy → SLAB → user malloc → mmap → application → leak detection. Complete summary of the entire memory system.


Last modified: 2024年3月4日

Author

Comments

Write a Reply or Comment

Your email address will not be published.