2

I want to create a java object wrapper around a native c++ object. I do this by putting the pointer to the c++ object in a direct ByteBuffer like so:

java side:

public class World {
  private final ByteBuffer pointer;
  public World() {
    pointer = init();
  }

  private native ByteBuffer init();
  public native void destroy();
}

native side:

extern "C" jobject Java_blabla_World_init(JNIEnv *e, jobject self) {
  return env->NewDirectByteBuffer(new World, sizeof(World));
}

Is it safe? Meaning, will java do funny things to my pointer, like maybe relocating it or garbage-collecting it?

Secondly, if I do not know the size of World in advance (it was forward-declared), is it OK to just give 0 as the buffer size? (provided, of course, that I do not try to read from the buffer)

larvyde
  • 811
  • 1
  • 6
  • 19

2 Answers2

1

The JVM is free to manage the ByteBuffer object but it will always contain the same address and capacity. It won't do anything to the memory pointed to by the ByteBuffer unless you call ByteBuffer methods on it and it will never move it.

But since you aren't going to call ByteBuffer methods, ByteBuffer and jlong are equivalent. It seems to me that using a jlong instead would make that clearer, even if you have to cast on in the JNI function. After all, to the Java side, you are creating and storing a handle, and to the JNI side, you are treating the handle as a pointer. A cast makes that clear.

Tom Blodget
  • 20,260
  • 3
  • 39
  • 72
0

Meaning, will java do funny things to my pointer, like maybe relocating it or garbage-collecting it?

You pointer is just a 32-bit number. If you don't change it, the JVM won't.

The only reason the JVM "knows" where references are is because they appear as fields of a class. This is not a field, nor if it stored in a reference.

Secondly, if I do not know the size of World in advance (it was forward-declared), is it OK to just give 0 as the buffer size?

No, a ByteBuffer is a fixed size and you cannot exceed it. I would set the ByteBuffer when you know how big it should be.

It's not clear to me what you are trying to do, but I suspect there are better ways of doing it.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I'm not sure you get what I'm trying to do here. Basically I need to pass a native pointer to a java object so that the java object can pass it back to native code when calling a native function. – larvyde May 10 '13 at 10:58
  • I am merely using the DirectByteBuffer as a pointer store, since DirectByteBuffers are normally backed by a native array and keep a pointer to that array. – larvyde May 10 '13 at 11:01
  • I guess my point is, I wonder whether the DirectByteBuffers "manage" the pointer in some way because it _assumes_ it is an array. – larvyde May 10 '13 at 11:03
  • As for better ways of doing it, the only other way I've seen is to store the pointer in a jlong, which require reinterpret_casts from pointer to integral type and back. I'm not sure that's really a better way. – larvyde May 10 '13 at 11:05
  • I suspect using a `jlong` is simpler. You can store this as a `long` in Java. DirectByteBuffer does this with it's `address` field. Java doesn't magically know where pointers are. It only knows about the references it manages, everything else is just data to it. – Peter Lawrey May 10 '13 at 18:43