Java ByteBuffers: Performance Guide
ByteBuffers underpin Java NIO. They let you read or write binary data without intermediate copies and expose typed views (asIntBuffer
, asFloatBuffer
) over the same memory region. Combined with channels, they power high-throughput networking, file I/O, and serialization pipelines.
Core Options
- Heap Buffers (
ByteBuffer.allocate
): Backed by the JVM heap; cheap to allocate and GC-managed. Best for short-lived operations. - Direct Buffers (
ByteBuffer.allocateDirect
): Outside the heap; ideal for zero-copy I/O but more expensive to create. Reuse them to avoid hitting native memory limits. - Mapped Buffers (
FileChannel.map
): Memory-map large files for random access without manual paging.
Practical Tips
- Flip buffers after writing and before reading:
buffer.flip()
resets position/limit. - Use
ByteOrder.nativeOrder()
when interacting with hardware or native code. - Monitor direct-buffer usage with
-XX:MaxDirectMemorySize
and thejcmd VM.native_memory
command to prevent leaks. - Prefer
ByteBuffer::slice
instead of allocating new buffers when parsing protocols.
Use Cases
- Network I/O: Socket channels consume and produce ByteBuffers directly. Keep pool sizes tuned to your message envelope.
- Serialization: Build custom binary formats quickly using relative
put
/get
methods or typed views. - Cryptography & Compression: Feed ByteBuffers into JCA and
java.util.zip
APIs to avoid extra copies.