On Thu, Feb 23, 2017 at 11:10 AM, Chris Hegarty <[email protected]> wrote:
> > > On 23 Feb 2017, at 11:30, Vitaly Davidovich <[email protected]> wrote: > >> ... > > The buffers are reused by having them point to different native memory > > block addresses; those blocks are managed by native code. As mentioned, > > the ByteBuffer (DirectByteBuffer concretely) is used as the Java level > > interface/view of native memory, allowing Java and native code to > > communicate. > > So a DBB, under your code, may report a different address at some time > in the future, to that of what it currently reports? Correct. > I was not aware of this > usecase. Is any similar code available on the web, or elsewhere, so we > could try to determine why this is being done? > Unfortunately it's not open source code, and I don't immediately know of anything similar on the web (or otherwise). However, the gist is the following: 1) Allocate a 0-size DBB (i.e. ByteBuffer.allocateDirect(0)). This gives you a Java "handle", if you will, to some native memory. But, since this DBB will be attached/reattached to different memory dynamically, there's no need for an actual allocation. 2) Native code wants to expose a segment of memory to Java. In JNI, it sets the address and capacity of this DBB to the pointer where the native memory segment starts, and to the capacity (it knows how big the native segment is). Java code asks for this DBB to be "attached" to, say, some sort of message, and the JNI/native code perform these functions. 3) Java gets the attached DBB back, and can then use its API (getXXX/setXXX) to read/write that native block. Once the operation completes, the DBB is recycled for reuse (i.e. can be attached to a different native segment again). Obviously, we can use http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#GetDirectBufferAddress to get the address and then expose that via a JNI helper - in fact, that's what was done before. But, there's a JNI call penalty here for what is otherwise a memory read. DirectBuffer::address() solves that nicely, and also plays well with the C2 JIT (as mentioned) because the callsites where this is used only see DBB, and then the whole invokeinterface call is devirtualized and inlined into a quick type check and Java field read - the performance of this is, as you can imagine, significantly better than the JNI approach. If you think of what a DBB really is, it's pretty much what it's name suggests - it's an API to read/write to native memory, rather than Java heap memory (i.e. HeapByteBuffer). But, there's no reason the native memory backing the DBB has to also be allocated via Unsafe itself, although that's the more common scenario. On the Java side, consumers of this have a common and conventional API over a byte buffer, i.e. ByteBuffer, which can optionally be used in the manner above (obviously callers will need to know what mode they're using). > -Chris. > >
