通过JNI传递C和Java之间的指针

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (28)

目前,我正在尝试创建一个使用CUDA功能的Java应用程序。CUDA和Java之间的联系很好,但我还有另外一个问题,想问一下,如果我对它的想法是正确的。

当我从Java调用本地函数时,我将一些数据传递给它,函数计算出某些内容并返回结果。是否有可能,让第一个函数返回一个引用(指针)到这个结果,我可以传递给JNI并调用另一个函数来进一步计算结果?

我的想法是通过将数据留在GPU内存中,并将一个引用传递给它,以便其他函数可以使用它,从而减少将数据复制到GPU以及从GPU复制数据所产生的开销。

尝试一段时间后,我想我自己,这应该是不可能的,因为指针会在应用程序结束后被删除(在这种情况下,当C函数终止时)。它是否正确?或者我只是在C坏了看到解决方案?

扩大一点问题(或更清楚地说明):当函数结束时,由JNI本地函数分配的内存是否被释放?或者我仍然可以访问它,直到JNI应用程序结束或手动释放它时为止?

提问于
用户回答回答于

我使用了以下方法:

在你的JNI代码中,创建一个结构体来保存对你需要的对象的引用。当你第一次创建这个结构体时,将它的指针返回为java long。然后,从java中调用任何方法long作为参数,并在C中将它转换为指向结构的指针。

该结构将在堆中,因此不会在不同的JNI调用之间清除。

我不认为你可以使用长ptr = (long)&address;因为地址是一个静态变量。使用Gunslinger47建议的方式,即创建类或结构的新实例(使用new或malloc)并传递它的指针。

用户回答回答于

在C ++中,你可以使用你想要分配/释放内存的任何机制:堆栈,malloc / free,new / delete或其他自定义实现。唯一的要求是,如果你分配的内存块有一个机制,你有相同的机制来释放它,所以你不能叫free一个堆栈变量,你不能叫deletemalloc版内存。

JNI有自己的分配/释放JVM内存的机制:

  • NewObject的/ DeleteLocalRef
  • NewGlobalRef / DeleteGlobalRef
  • NewWeakGlobalRef / DeleteWeakGlobalRef

这些规则遵循相同的规则,唯一的问题是PopLocalFrame当本地方法退出时,本地引用可以被明确地,有或无意地删除。

JNI不知道你如何分配你的内存,所以当你的函数退出时它不能释放它。堆栈变量显然会被破坏,因为你仍在编写C ++,但你的GPU内存仍然有效。

唯一的问题是如何在随后的调用中访问内存,然后你可以使用Gunslinger47的建议:

JNIEXPORT jlong JNICALL Java_MyJavaClass_Function1() {
    MyClass* pObject = new MyClass(...);
    return (long)pObject;
}

JNIEXPORT void JNICALL Java_MyJavaClass_Function2(jlong lp) {
    MyClass* pObject = (MyClass*)lp;
    ...
}

扫码关注云+社区