I'm struggling to understand the documentation of sun.misc.Unsafe -- I guess as it's not intended for general use, nobody's really bothered with making it readable -- but I actually really need a way to find the address of an element in an array (so that I can pass a pointer to it to native code). Has anyone got any working code that does this? Is it reliable?
3 Answers
Instead of using an array you can use a ByteBuffer.allocateDirect() direct buffer. This has the address in a field and this address doesn't change for the life of the ByteBuffer. A direct ByteBuffer uses minimal heap space. You can get the address using reflection.
You can use Unsafe to get an address, the problem is that the GC can move it at any time. Objects are not fixed in memory.
In JNI you can use special methods to copy data to/from Java objects to avoid this issue (and others) I suggest you use these if you want to exchange data between Objects with C code.
3 Comments
GetPrimitiveArrayCritical which might hurt the GC. Bite the bullet and copy into direct (buffer) memory. That's the only feasible solution. For instance the impl. FileOutputStream (SocketOutputStream extends it) uses copy of the elements on the stack. Penalty to copy is not so high, since the highest cost comes w/ the load cost of the data (and cache misses, even) which you'd have to pay either way. The copying will also cause to prefetch the cachelines, so it's might be even better depeding how the native code works.Here is a working sample. Please be careful however as you may easily crash your JVM with unappropriate usage of Unsafe class.
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class UnsafeTest {
public static void main(String... args) {
Unsafe unsafe = null;
try {
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (sun.misc.Unsafe) field.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
int ten = 10;
byte size = 1;
long mem = unsafe.allocateMemory(size);
unsafe.putAddress(mem, ten);
long readValue = unsafe.getAddress(mem);
System.out.println("Val: " + readValue);
}
}
3 Comments
char* mem = malloc(size);... it's never touched by the GC and causes native C leak unless realesed.Why? There are plenty of facilities in JNI for dealing with the contents of Java arrays. You don't need to use undocumented internal Sun classes that mightn't be there next week.
Unsafe?