Fundamentals 15 min read

How Zero‑Copy Boosts Data Transfer: IO Mechanisms, mmap, sendfile & splice Explained

This article explains the concept of zero‑copy, compares traditional I/O copying with mmap, sendfile, DMA scatter/gather and splice techniques, and shows how Java NIO leverages mmap and sendfile to achieve high‑performance data transfer while minimizing CPU involvement.

macrozheng
macrozheng
macrozheng
How Zero‑Copy Boosts Data Transfer: IO Mechanisms, mmap, sendfile & splice Explained

01. Background Introduction

Many readers have encountered the term "zero‑copy" and wonder what it actually means. Literally, "zero" means zero copy operations and "copy" means moving data between storage areas, so zero‑copy means data does not need to be copied from one storage region to another.

In Linux 2.4 kernel, the sendfile system call can move disk data to a kernel buffer via DMA and then directly to a NIC buffer without CPU copying; this process is called zero‑copy.

From an OS perspective, zero‑copy does not eliminate data movement; it removes the CPU copy step, reducing unnecessary copies and improving efficiency.

02. IO Copy Mechanism Introduction

2.1 Traditional Data Copy Process

When a client downloads a file, the server performs two main steps: read the file from disk and transmit it over the network. The traditional flow involves:

Application calls

read

, causing a CPU context switch from user to kernel mode.

OS uses DMA to move data from disk to a kernel buffer.

CPU copies data from the kernel buffer to a user buffer, causing a second context switch back to user mode.

This results in one DMA copy, one CPU copy, and two CPU context switches for each read or write operation.

2.2 mmap Memory‑Mapped Copy Process

mmap maps the user buffer directly to the kernel buffer, eliminating the CPU copy between them. The flow reduces the number of CPU copies while keeping the same DMA operations.

Data copies: 2 DMA copies, 1 CPU copy.

CPU switches: 4 (user↔kernel).

2.3 Linux sendfile Copy Process

In Linux 2.1,

sendfile

moves data from disk to a kernel buffer via DMA, then directly to a socket buffer, and finally to the network interface via DMA.

Data copies: 2 DMA copies, 1 CPU copy.

CPU switches: 2 (user↔kernel).

2.4 sendfile with DMA Scatter/Gather

Linux 2.4 introduced SG‑DMA support, allowing DMA to read directly from kernel space to the NIC, eliminating the CPU copy step.

Data copies: 2 DMA copies, 0 CPU copies.

CPU switches: 2 (user↔kernel).

2.5 Linux splice Zero‑Copy Process

Linux 2.6.17 added the

splice

system call, which creates a pipe between the kernel buffer and the socket buffer, avoiding CPU copies without requiring special hardware.

Data copies: 2 DMA copies, 0 CPU copies.

CPU switches: 2 (user↔kernel).

03. IO Copy Mechanism Comparison

The table below summarizes the copy counts and context switches for each method. All zero‑copy techniques rely on OS support; the choice depends on the kernel implementation.

04. Related Concepts

4.1 DMA (Direct Memory Access)

DMA is a hardware feature that allows peripheral devices to transfer data directly to or from memory without CPU intervention, reducing CPU load.

4.2 Kernel Space and User Space

The operating system kernel runs in kernel space with full hardware access, while applications run in user space with restricted privileges. Data must be transferred between these spaces via system calls, which is where zero‑copy techniques operate.

05. Java Zero‑Copy Implementation

Java supports two zero‑copy mechanisms provided by the underlying Linux kernel: mmap and sendfile.

5.1 Java NIO support for mmap

Java NIO’s

MappedByteBuffer

class maps a file directly into memory, invoking the Linux

mmap

API.

<code>public static void main(String[] args) {
    try {
        FileChannel readChannel = FileChannel.open(Paths.get("a.txt"), StandardOpenOption.READ);
        // Create memory‑mapped file
        MappedByteBuffer data = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, 1024 * 1024 * 40);
        FileChannel writeChannel = FileChannel.open(Paths.get("b.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        // Copy data
        writeChannel.write(data);
        // Close channels
        readChannel.close();
        writeChannel.close();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}
</code>

5.2 Java NIO support for sendfile

Java NIO’s

FileChannel.transferTo

method ultimately calls the Linux

sendfile

system call when the OS provides it.

<code>public static void main(String[] args) {
    try {
        // Source file
        FileChannel srcChannel = FileChannel.open(Paths.get("a.txt"), StandardOpenOption.READ);
        // Destination file
        FileChannel destChannel = FileChannel.open(Paths.get("b.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        // Transfer data
        srcChannel.transferTo(0, srcChannel.size(), destChannel);
        // Close channels
        srcChannel.close();
        destChannel.close();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}
</code>

06. Summary

Zero‑copy does not mean data is never copied; it means the CPU copy step is omitted, reducing unnecessary copies and improving throughput. In Linux, the widely recognized zero‑copy methods are

sendfile

and

splice

, which rely entirely on DMA without CPU involvement.

performanceLinuxMMAPsendfileZero CopyIOJava NIO
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.