通过JNI是否有直接获取Java数组指针的方法?

5
我需要通过JNI获取包含Java数组直接内存地址的指针,而不需要进行某种形式的复制(即直接访问)。
GetArrayElements返回指向已复制数组的指针-我需要能够直接从本地层修改Java层上的int[]。
从jintArray转换为int*可以成功返回内存地址,但我不确定这是否特别稳定...?
在这里我能做些什么吗...?

所以您有意要实现一些功能,以导致JVM在不支持固定的GC上发生内存损坏,因此必须使用复制来实现可用的函数?实施者可能认为“获取指向数组或可能包含其他有效对象的任意内存位置的指针”太长了。 - Voo
1
刚想起来一件事。你实际上可以使用GetPrimitiveArrayCritical - 这意味着没有GC可能运行,你必须遵守几个限制(在执行此操作之前,请阅读并理解这些限制),但只要Java中的原始表示等同于C++中的原始表示,它就会起作用。如果不是,那么你无法避免复制。 - Voo
谢谢您的建议:) 我不理解您的第一条评论,当然,在本地层允许对Java分配的内存进行读写访问不会导致破坏,除非gc发生并将内存回收用于其他用途(类似数组的全局缓冲区属性,所有gc都在基于本地的对象超出范围时发生,因此数组内存肯定会保持稳定直到那时为止)。感谢GetPrimitiveArrayCritical解决方案-我会看一下:) 有没有办法创建一个指向本地分配的内存的int[]..? 祝好,史蒂夫 - user965369
1
如果GC不允许固定(如果它这样做,GetArrayElement就不会复制东西),这意味着在GC之后int[]对象可能不再处于同一位置(显然本机指针与Java引用相反没有更新)。这意味着如果您在GC之后写入该位置,则会覆盖外部内存。您可以像Peter Lawrey所说的那样使用ByteBuffers - 通过在GC堆之外分配内存来解决这些问题。 - Voo
谢谢。说实话,我以前没有深入研究过虚拟机,所以这对我来说是一个学习曲线;) - user965369
3个回答

6
您可以使用直接内存(IntBuffer)(使用本机字节顺序)来进行操作。在JNI中,您可以将地址用作指针。在Java中,您需要使用get()和put()方法。

1
从JNI访问ByteBuffer:http://download.oracle.com/javase/1.4.2/docs/guide/jni/jni-14.html#GetDirectBufferAddress。 - Andy Thomas

3
也许可以。您可以调用某些方法,可能会直接指向Java内存,但这取决于JVM的能力。
来自http://java.sun.com/docs/books/jni/html/objtypes.html#4099
JNI支持一系列Get/ReleaseArrayElements函数(包括例如Get/ReleaseIntArrayElements),允许本地代码获取原始数组元素的直接指针。由于底层垃圾收集器可能不支持固定,虚拟机可能会返回指向原始基元数组副本的指针。
请注意,在完成后需要释放指针。
编辑:
在JDK 1.3中,添加了Get/ReleasePrimtiveArrayCritical()函数,即使JVM不支持固定,也可以获得直接指针。
"These restrictions make it more likely that the native code will 
obtain an uncopied version of the array, even if the VM does not 
support pinning. For example, a VM may temporarily disable garbage 
collection when the native code is holding a pointer to an 
array obtained via GetPrimitiveArrayCritical."

然而,您应尽快释放指针,并且与JVM的交互受到限制。

如果您需要频繁但稀疏地与大型数组交互,则可以使用GetArrayRegion()函数仅获取数组中的小区域。


谢谢兄弟。我一直在使用这些函数,但在我使用的特定平台上,它们返回指向数组副本的指针。另外,有没有办法让Java int[]直接指向本地数组? - user965369

1

另一种方法是获取其地址并使用 GetDirectBufferAddress 方法将一个指针设置为该地址。您可以在下面的链接中找到更多信息:

double * cArr = (double *)((char *)env->GetDirectBufferAddress(inpObject));

获取复杂对象的直接缓冲区地址示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接