问题 JNI对象创建和内存管理


我有以下JNI方法本地创建Java对象的集合,然后将它们返回到Java:

JNIEXPORT jobject JNICALL Java_com_test_myClass_myMethod(JNIEnv * env, jclass klass) {
    jclass arrayClass = env->FindClass("java/util/ArrayList");
    jmethodID initMethod = env->GetMethodID(arrayClass, "<init>", "()V");
    jmethodID addMethod = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
    jobject myArray = env->NewObject(arrayClass, initMethod);

    env->CallBooleanMethod(myArray, addMethod, env->NewStringUTF("Hello"));
    env->CallBooleanMethod(myArray, addMethod, env->NewStringUTF("World"));

    return myArray;
}

我是否需要释放在本机代码中创建的对象,还是由GC自动完成? 如果我这样做,我该怎么做,因为我需要将它返回给Java?


1103
2018-02-20 23:19


起源

我认为由本机代码来做自己的内存管理。在这种情况下,我想你需要添加另一个释放已分配对象的本机方法,当你完成它们时,你手动调用它们。更一般地说,如果你正在与JNI做事,那么我希望你为一个受伤的世界做好准备。这个答案可能有所帮助 stackoverflow.com/questions/214699/... - aroth
@aroth - 错了。如果在JNI中分配Java对象,则它们是GC拥有的Java对象。 - bmargulies
@bmargulies - 有道理,但是在本机代码的情况下,分配非Java对象/内存,例如通过调用 malloc()? - aroth
@aroth不是这个问题的关键。 - bmargulies


答案:


您不需要释放在本机代码中创建的Java对象。事实上,你不能。当没有进一步的引用时,垃圾收集器可以释放该对象。

偶尔在本机代码中释放是有用的 引用 到Java对象。当本机代码保存但不再需要对大对象或大量引用的引用时,这可以减少内存需求。

来自:“全球和本地参考”中 JNI规范

在大多数情况下,程序员应该依赖VM在本机方法返回后释放所有本地引用。但是,有时程序员应该明确地释放本地引用。例如,考虑以下情况:

  • 本机方法访问大型Java对象,从而创建对Java对象的本地引用。然后,本机方法在返回调用方之前执行其他计算。对大型Java对象的本地引用将阻止对象被垃圾回收,即使该对象不再用于计算的其余部分。
  • 本机方法会创建大量本地引用,但并非所有引用都同时使用。由于VM需要一定的空间来跟踪本地引用,因此创建太多本地引用可能会导致系统内存不足。例如,本机方法循环遍历大量对象,将元素作为本地引用检索,并在每次迭代时对一个元素进行操作。在每次迭代之后,程序员不再需要对数组元素的本地引用。

提供了更多细节 看到 “释放参考文献” 在JNI程序员指南中。


12
2018-02-20 23:36



我阅读了有关Freeing References的指南,但对此有疑问:可以在我的初始帖子中多次调用该方法会造成资源耗尽问题吗?如果是的话,我在哪里可以免费提供参考资料,因为我还需要退货? - nbarraille
每次调用后都会自动释放本地引用。您不必明确地执行此操作,除非1)您已创建全局引用,或2)需要在调用完成之前释放本地引用,原因在链接中描述。您正在返回的引用正在被复制。 myArray和返回的引用都指向同一个Java对象。 - Andy Thomas
链接死了...... - BeniBela
新链接: books.google.co.il/... - Vaiden
谷歌图书链接现在也已经死了。可以在Internet存档上找到Sun文档: web.archive.org/web/20070812015712/http://java.sun.com/docs/... (第5.2节是“解放参考”之一)。 - sam