How Zero‑Copy Supercharges Java Performance: From mmap to Netty
This article explains the concept of zero‑copy, its implementation in Java I/O, NIO, Netty, and popular messaging systems, and shows how techniques like mmap+write and Sendfile eliminate unnecessary data copying to dramatically improve throughput and latency.
I/O Concepts
Buffers are the foundation of all I/O operations; a process issues read or write requests to the operating system, which either drains data from a kernel buffer to user space (write) or fills a user buffer from the kernel (read).
When a read request arrives, the kernel first checks if the required data already resides in kernel space; if so, it copies the data directly to the process buffer. Otherwise, it commands the disk controller to write data into the kernel read buffer via DMA, after which the kernel copies the data to the user buffer. Write operations similarly copy user data to the kernel socket buffer and then to the network card via DMA.
Zero‑copy was introduced to eliminate these costly copies between kernel and user space.
Virtual Memory
Modern operating systems use virtual memory, allowing multiple virtual addresses to map to the same physical memory and enabling a virtual address space larger than physical RAM. By mapping kernel and user virtual addresses to the same physical page, DMA can fill a buffer visible to both spaces, removing the need for extra copies.
Zero‑Copy Techniques
mmap + write
Sendfile
mmap+write Method
Memory‑mapped files map a file or object into a process's address space, establishing a one‑to‑one correspondence between file offsets and virtual addresses. This removes the need for the kernel read buffer to copy data into the user buffer, though a copy from the kernel read buffer to the kernel socket buffer may still occur.
Sendfile Method
The sendfile system call, introduced in kernel 2.1, simplifies data transfer between two channels by eliminating data copies and reducing context switches. Later kernel improvements recorded buffer descriptors directly in the socket buffer, removing even the remaining kernel‑space copy.
Java Zero‑Copy
MappedByteBuffer
Java NIO's FileChannel provides a map() method that creates a virtual memory mapping between a file and a MappedByteBuffer. The buffer behaves like a ByteBuffer, but its data resides on disk and is accessed directly.
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(MapMode mode, long position, long size) throws IOException;Parameters:
MapMode : READ_ONLY, READ_WRITE, PRIVATE.
Position : start offset in bytes.
Size : number of bytes to map.
PRIVATE mode creates a copy‑on‑write mapping where modifications are not reflected in the underlying file.
DirectByteBuffer
DirectByteBufferextends MappedByteBuffer and allocates memory outside the JVM heap, avoiding garbage‑collector overhead. It can also be created manually:
ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(100);Channel‑to‑Channel Transfer
Java's 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();
}
}
}Signature:
public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException;This method avoids copying data into a user buffer and leverages kernel buffers for both source and destination.
Netty Zero‑Copy
Netty provides zero‑copy buffers using CompositeChannelBuffer and Slice. Composite buffers combine multiple ChannelBuffer instances without copying their contents, while Slice creates view buffers that share the same underlying memory.
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]);
}
...
}The buffer holds references to all received buffers; no new memory is allocated, achieving zero‑copy.
Other Zero‑Copy Implementations
RocketMQ writes messages sequentially to a commit log and uses a consume‑queue index; it employs mmap+write for consumer requests. Kafka also uses the Sendfile technique to transfer data from disk to the network without extra copies.
Conclusion
Zero‑copy in Java essentially works by sharing object references so that a single modification is visible to all users, eliminating duplicate copies and significantly improving I/O performance.
Source: ksfzhaohui Link: https://juejin.im/post/5cad6f1ef265da039f0ef5df Copyright notice: Content is shared for learning purposes only; original author retains rights.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
