允许本机代码直接访问java堆中的对象?

时间:2012-08-24 15:10:58

标签: java c java-native-interface jna native-code

我有一个Java对象数组,我希望允许本机C代码直接访问该数组(没有复制或访问器功能)。这可能吗?我不介意解决方案是否特定于JVM。

4 个答案:

答案 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)

以上所有问题,有一个很好的解决方案(点击链接下方):

GetDirectBufferAddress

如果您有一个对象而不是原始数组,您可以找到如何提供直接访问。