Zero-Copy Transfer
Zero-copy transfer moves data between file descriptors without copying through user space, so a large file send costs no CPU copy and no user-space buffer allocation.
Definition
Zero-copy transfer is the optimization where data is moved between file descriptors — file to socket, file to file — using kernel facilities (sendfile, splice) that transfer directly within the kernel, so that the data is never copied to user space, eliminating the CPU copy and the user-space buffer allocation for large transfers.
Context and scope
Applied in static file serving, proxy data forwarding, and any large transfer where the copy through user space is a measurable CPU and memory cost.
Common misconceptions
- Zero-copy is always faster — it is faster for large transfers; for small transfers the syscall setup cost can exceed the copy it avoids
- sendfile works for any file — it works for regular files to sockets; for other combinations (pipe to socket, file to pipe) splice or copy_file_range is needed
Anti-patterns
- Using zero-copy for tiny transfers where the syscall overhead exceeds the copy saved
- Calling sendfile without a fallback for the case where the kernel does not support it, failing on older systems
Related concepts
Authoritative source
What it is
Zero-copy transfer is the optimization where data is moved between file descriptors — file to socket, file to file — using kernel facilities (sendfile, splice) that transfer directly within the kernel, so that the data is never copied to user space, eliminating the CPU copy and the user-space buffer allocation for large transfers. Applied in static file serving, proxy data forwarding, and any large transfer where the copy through user space is a measurable CPU and memory cost. Performance is a distribution, not a number: the tail determines user experience, and the mean hides the outliers that cause abandonment.
How it works
Measurement targets percentiles at the workload’s actual concurrency, not a single sequential run. The fast path is kept fast by deferring work that is not on it — lazy initialization, coalescing writes, avoiding allocation in hot loops. Profiling finds the bottleneck; micro-optimization without a profile optimizes the wrong thing. Constant factors matter, but algorithmic complexity dominates as scale grows.
When to optimize and pitfalls
Optimize when a measurement shows a concrete cost — latency budget burn, compute spend, user-visible jank. The pitfall is optimizing for the benchmark rather than the workload: a synthetic test that does not reproduce the production access pattern produces a local maximum that hurts globally. Another is trading memory for speed without accounting for the GC or eviction cost the extra allocation introduces.