Understanding Zero‑Copy: DMA, mmap, sendfile and Java NIO Performance
This article explains how zero‑copy techniques such as DMA, mmap, and sendfile work, compares them with traditional file I/O, shows their Java NIO implementations, and presents performance test results demonstrating the advantages of mmap for small files and sendfile for large files.
Kafka achieves high throughput partly due to zero‑copy techniques; this article explains the underlying mechanisms.
Traditional file read/write – Data moves between kernel space and user space, requiring copies for each I/O operation.
Data is first read from disk into the kernel page cache, then copied to the user buffer, and later copied back to kernel before being sent to the device.
DMA (Direct Memory Access) – Allows hardware devices to transfer data directly between memory regions without CPU intervention, reducing CPU load.
Zero‑copy – Two common methods are mmap and sendfile , both based on DMA.
mmap maps a file directly into the process address space, sharing the kernel buffer with user space so that no extra copy is needed when reading or writing.
In an example, src.data is transferred via DMA while dest.data is modified through an mmap mapping.
sendfile transfers data from one DMA device to another without copying into user space; only the file offset and length are placed in the socket buffer.
Since Linux 2.1, sendfile avoids copying data from the page cache to the socket buffer; the kernel keeps two copies of the data, and the actual transmission is performed by DMA.
Java implementation of zero‑copy
JDK’s FileChannel provides transferTo and transferFrom (based on sendfile) and map (based on mmap).
// Transfer bytes from this FileChannel to a writable channel
public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException;
// Transfer bytes from a readable channel into this FileChannel
public abstract long transferFrom(ReadableByteChannel src, long position, long count) throws IOException;
// Create a memory‑mapped buffer for this channel
public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException;File copy performance test
Three implementations are compared: traditional copy, mmap copy, and sendfile copy, using files of different sizes.
public class OldFileCopy {
public static final String source = "C:/data/src.log";
public static final String dest = "C:/data/dest.log";
public static void main(String[] args) {
try {
FileInputStream inputStream = new FileInputStream(source);
FileOutputStream outputStream = new FileOutputStream(dest);
long start = System.currentTimeMillis();
byte[] buff = new byte[4096];
int read;
while ((read = inputStream.read(buff)) >= 0) {
outputStream.write(buff, 0, read);
}
outputStream.flush();
System.out.println("耗时:" + (System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
}
}
} public class MmapFileCopy {
public static final String source = "C:/data/src.log";
public static final String dest = "C:/data/dest.log";
public static void main(String[] args) {
try {
FileChannel sourceChannel = new RandomAccessFile(source, "rw").getChannel();
FileChannel destChannel = new RandomAccessFile(dest, "rw").getChannel();
long start = System.currentTimeMillis();
MappedByteBuffer map = destChannel.map(FileChannel.MapMode.READ_WRITE, 0, sourceChannel.size());
sourceChannel.write(map);
map.flip();
System.out.println("耗时:" + (System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
}
}
} public class SendFileCopy {
public static final String source = "C:/data/src.log";
public static final String dest = "C:/data/dest.log";
public static void main(String[] args) {
try {
FileChannel sourceChannel = new RandomAccessFile(source, "rw").getChannel();
FileChannel destChannel = new RandomAccessFile(dest, "rw").getChannel();
long start = System.currentTimeMillis();
sourceChannel.transferTo(0, sourceChannel.size(), destChannel);
System.out.println("耗时:" + (System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
}
}
}The test results show that both mmap and sendfile outperform traditional copy; mmap is faster for small files, while sendfile scales better for large files.
Big Data Technology Architecture
Exploring Open Source Big Data and AI Technologies
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.