我有一个Java对象数组,我希望允许本机C代码直接访问该数组(没有复制或访问器功能)。这可能吗?我不介意解决方案是否特定于JVM。
答案 0 :(得分:1)
当然可以与JNI合作。
值得查阅此链接:http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/array.html 简而言之 -
#include <jni.h>
#include "IntArray.h"
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jsize len = (*env)->GetArrayLength(env, arr);
int i, sum = 0;
jint *body = (*env)->GetIntArrayElements(env, arr, 0);
for (i=0; i<len; i++)
sum += body[i];
(*env)->ReleaseIntArrayElements(env, arr, body, 0);
return sum;
}
答案 1 :(得分:1)
如果您使用的是较新版本的java,请使用ByteBuffer个对象。
调用ByteBuffer.allocateDirect()
来分配缓冲区。直接缓冲区位于垃圾收集器的域之外。要从JNI访问缓冲区,请致电GetDirectBufferAddress()
。它返回一个指向字节缓冲区的指针。这不会在引擎盖下进行复制。可以在Java和Native端看到对缓冲区的更改。
javadocs对使用直接缓冲区有一些警告:
可以通过调用此类的allocateDirect工厂方法来创建直接字节缓冲区。与非直接缓冲区相比,此方法返回的缓冲区通常具有更高的分配和解除分配成本。直接缓冲区的内容可能位于正常的垃圾收集堆之外,因此它们对应用程序的内存占用量的影响可能并不明显。因此,建议直接缓冲区主要分配给受基础系统本机I / O操作影响的大型长期缓冲区。通常,最好只在它们在程序性能中产生可测量的增益时才分配直接缓冲区。
答案 2 :(得分:0)
我终于找到了答案。通常不可能用JNI做我想做的事情。但是,有些VM提供了所需的功能,我使用了JikesRVM:
1)本机代码需要数组的内存位置。这可以使用JikesRVM中的“Magic”工具来实现,它提供了一个ObjectReference和一个Address类,允许为每个对象获取一个内存地址。然后可以将此地址作为long / int参数(使用JNI)转发到本机代码,并将其转换为指针。
2)GC可能无法移动物体。这有点棘手,因为它需要支持GC中的固定。对于JikesRVM,可以使用@NonMoving和@NonMovingAllocation(也是'Magic'的一部分)注释对象。此外,对象(即阵列)> 8KB放置在大对象空间中,不会移动对象。
答案 3 :(得分:0)