Mastering Zero-Copy in Java: Boost Performance with NIO, Netty, and More

Zero-copy techniques eliminate unnecessary data copying between user and kernel space, dramatically improving I/O performance; this article explains core I/O concepts, explores Java implementations like MappedByteBuffer, DirectByteBuffer, channel-to-channel transfers, and demonstrates Netty’s composite buffers, plus examples from Kafka and RocketMQ.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Mastering Zero-Copy in Java: Boost Performance with NIO, Netty, and More

Preface

Zero-copy means data does not need to be copied back and forth, greatly improving system performance; the term appears in Java NIO, Netty, Kafka, RocketMQ as a performance highlight.

I/O Concepts

1. Buffer

Buffers are the basis of all I/O; a process issues read/write requests to the operating system, which either empties the kernel buffer (write) or fills it (read). The kernel may copy data directly to the process buffer or, for reads, use DMA to write data from the disk controller into the kernel read buffer.

After a read request, if the data is already in kernel space it is copied to the process buffer; otherwise the kernel commands the disk controller to read data directly into the kernel read buffer via DMA. For write requests, user data is copied to the kernel socket buffer and then DMA transfers it to the network card.

These copies waste memory bandwidth, which zero-copy aims to eliminate.

2. Virtual Memory

Modern operating systems use virtual memory, mapping virtual addresses to physical memory. This allows multiple virtual addresses to refer to the same physical page and enables a virtual address space larger than physical memory. By mapping kernel and user space to the same physical page, DMA can fill a buffer visible to both, avoiding extra copies.

3. mmap+write

The mmap+write method replaces the traditional read+write sequence. mmap maps a file into the process address space, establishing a one‑to‑one relationship between a file’s disk address and a virtual address range. This eliminates the kernel read buffer copy, though data still needs to be copied from the kernel read buffer to the kernel socket buffer.

4. sendfile

The sendfile system call, introduced in kernel 2.1, simplifies data transfer between two channels by performing the copy entirely in kernel space, reducing both data copies and context switches.

Later Linux kernels further reduced the remaining copy by recording buffer descriptors directly in the socket buffer.

Java Zero-Copy

1. MappedByteBuffer

FileChannel.map() creates a memory‑mapped file, returning a MappedByteBuffer that extends ByteBuffer. The buffer’s data resides on disk, while get() reads from the file and put() writes back, with changes visible to other readers.

public class MappedByteBufferTest {
    public static void main(String[] args) throws Exception {
        File file = new File("D://db.txt");
        long len = file.length();
        byte[] ds = new byte[(int) len];
        MappedByteBuffer mappedByteBuffer = new FileInputStream(file).getChannel()
                .map(FileChannel.MapMode.READ_ONLY, 0, len);
        for (int offset = 0; offset < len; offset++) {
            byte b = mappedByteBuffer.get();
            ds[offset] = b;
        }
        Scanner scan = new Scanner(new ByteArrayInputStream(ds)).useDelimiter(" ");
        while (scan.hasNext()) {
            System.out.print(scan.next() + " ");
        }
    }
}

The map() method signature:

public abstract MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) throws IOException;

Parameters: MapMode (READ_ONLY, READ_WRITE, PRIVATE), position (start offset), size (length). PRIVATE creates a copy‑on‑write buffer; modifications are not persisted to the file.

2. DirectByteBuffer

DirectByteBuffer extends MappedByteBuffer and allocates off‑heap memory that does not count toward the JVM heap.

ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(100);

3. Channel‑to‑Channel Transfer

FileChannel.transferTo() moves data directly between channels without an intermediate user‑space buffer.

public class ChannelTransfer {
    public static void main(String[] argv) throws Exception {
        String[] files = new String[1];
        files[0] = "D://db.txt";
        catFiles(Channels.newChannel(System.out), files);
    }

    private static void catFiles(WritableByteChannel target, String[] files) throws Exception {
        for (int i = 0; i < files.length; i++) {
            FileInputStream fis = new FileInputStream(files[i]);
            FileChannel channel = fis.getChannel();
            channel.transferTo(0, channel.size(), target);
            channel.close();
            fis.close();
        }
    }
}

Method signature:

public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException;

This transfers data directly between kernel buffers of the source and target channels, eliminating user‑space copies.

Netty Zero-Copy

Netty provides composite and slice buffers to avoid copying when assembling or splitting messages. A CompositeChannelBuffer holds references to component buffers rather than copying their contents.

public class CompositeChannelBuffer extends AbstractChannelBuffer {
    private final ByteOrder order;
    private ChannelBuffer[] components;
    private int[] indices;
    private int lastAccessedComponentId;
    private final boolean gathering;
    public byte getByte(int index) {
        int componentId = componentId(index);
        return components[componentId].getByte(index - indices[componentId]);
    }
    // ...
}

Components store all received buffers; indices record each buffer’s start position; the buffer reads/writes directly from/to the underlying component buffers, achieving zero-copy.

Other Zero-Copy

RocketMQ writes messages sequentially to a commit log and uses an mmap+write approach to serve consumer requests without extra copies. Kafka also employs the sendfile system call for network transmission of persisted data.

Conclusion

Zero-copy can be thought of as operating on object references: all parts of the system share a single underlying object, so modifications are reflected everywhere without creating duplicate copies.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaperformancenioNettyZero CopyMemory Mapped Files
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

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.