Description
java.nio.ByteBuffer
is THE data container in Java NIO APIs. Those who need to use features provided only by the NIO APIs (like non-blocking sockets) are doomed to use ByteBuffer
for data transferring. Those who need to achieve better performance or use IO interfaces unavailable in Java StdLib will end up using libraries that might roll out their own data containers but usually still allowing to wrap or directly use ByteBuffer
(like Netty or Aeron does).
It's possible to wrap a heap-allocated byte array (the backing storage for kotlinx-io
segments) into a HeapByteBuffer
, but the use of heap buffers comes with a cost. The majority of NIO API calls eventually perform a native call. If such a call (for example, a native wrapper for POSIX write
) needs data, then NIO will supply it in the form of DirectByteBuffer or a memory address extracted from the DirectByteBuffer. If a user had provided DirectByteBuffer
, then that buffer will be used, but if it was a HeapByteBuffer
, then its content will be copied into an internal cached DirectByteBuffer
instance and only then passed to the native API. If the buffer is empty, then the copying cost could be neglected, but as the buffer grows, it starts playing a more significant role in overall performance.
Besides performance issues with NIO API, a buffer residing in native memory is a necessity when it comes to implementing Java API for not yet supported native IO APIs such as io_uring, send w/ MSG_ZEROCOPY flag, epoll in the edge-triggering mode, etc. The only available option for allocating such a buffer and using it in a wide range of JVM versions supported by the Kotlin is by using DirectByteBuffer
.
Unfortunately, using direct byte buffers is not always an option:
- some APIs don't directly support it on JVM (like
MessageDigest
) - manipulations with the buffer itself works significantly slower on Android
So the only viable option might be to support both byte-arrays and ByteBuffer
s as a backing storage and provide a way to choose what particular implementation to use when starting an app.
Tasks:
- investigate ByteBuffers advantages/need to support it in
kotlinx-io
- publish results of BB performance investigation
- evaluate
kotlinx-io
performance withDirectByteBuffer
- publish performance characteristics of
kotlinx-io
w/ BB as a backing storage on JVM - refactor the library to allow using different
Segment
implementations - implement
DirectByteBuffer
-backed segments - investigate JDK22
MemorySegment
s usage instead of BB - implement polymorphic segment
- port some benchmarks to Android
- evaluate baseline performance on Android
- evaluate DirectByteBuffers performance on Android
- investigate R8 features/capabilities/issues
- finalize and publish a design
- test-library support for multiple segment types
- tune performance (rewrite UTF8-manipulation routines, for example)