Search code examples
javac++java-native-interface

JNI GetDirectBufferAddress vs. ByteBuffer.array()


I have to mix c++ code with java. The java part allocates a java.nio.ByteBuffer and the c++ part gets it's address via env->GetDirectBufferAddress(buffer) as a jbyte* and fills in data.

ByteOrder is ok. Data can be retrieved in java via buffer.get() .getLong() etc.

However, the method buffer.array() fails and hasArray() returns false. If I use buffer.allocate(size) instead of .allocateDirect(size) the method array() works well, but my c++ code gets a DirectBufferAddress of NULL and fails.

My question: how can I best combine both worlds, with least copying of data? Or, how to easiest fill a java byte[] with native c++ data ?


Solution

  • ByteBuffer class is indeed confusing. It is actually a wrapper around one of two entirely different classes: DirectByteBuffer and ArrayByteBuffer. Why this happened, is a question for historians.

    As far as the programmers are concerned, we must use DirectByteBuffer to achieve fastest, no-copy access from C, but access to DirectByteBuffer from Java may be quite slow, and it lacks the flexibility of byte[]. The array-based ByteBuffer has no advantage for C libraries, but it may be much more efficient on the Java side.

    On the other hand, JNI does provide access to primitive arrays, including byte[]. In many cases, such access does not involve copy, especially if you use GetPrimitiveArrayCritical(). Well, there is no guarantee. But If you use a modern optimized JVM on modern hardware with abundant physical RAM and almost unlimited virtual RAM, your chances to have efficient access from both C/C++ and Java are very high.