JNI:从C++调用JAVA方法,返回对象,引用和GC
JNI: Invoke JAVA method from C++, returned objects, References and GC
当C++程序(!)调用返回对象的java方法时,规则是什么?是否有对该对象的突出引用?我必须调用"DeleteLocalRef"来确保对象是GCd吗?还是会自动为GCd?我不清楚的原因是,在所有的示例和官方文档中,"DeleteLocalRef"是不必要的,只有当从java调用本机"C/C++"方法时,它才对我有意义。但是,如果调用线程是一个调用java的C++方法,JVM将如何知道该对象可以是GCd?
同样:如果我想缓存对象,我必须调用"NewGlobalRef"吗?
找不到对此的任何引用。。。
感谢的任何参考和/或澄清
我认为j.holetzeck的回答忽略了重要部分。
来自同一文档:
实施本地参考
为了实现本地引用,Java VM为控制从Java到的每次转换创建一个注册表。注册表将不可移动的本地引用映射到Java对象,并防止对象被垃圾收集。传递给本机方法的所有Java对象(包括那些作为JNI函数调用结果返回的对象)都会自动添加到注册表中。在本机方法返回后,注册表将被删除,从而允许对其所有条目进行垃圾收集。
我将以我的应用程序为例解释我对此的解释:
我的应用程序流程的高级概述:
- Android活动在Java中启动
- 每帧一次,Android活动调用C++来运行我们应用程序的更新循环
- 在这个C++更新循环中,我们的C++代码使用JNI对Java进行任意数量的调用
我如何解释引用的文档是,自动垃圾收集可以而且只会在步骤2中发生,当我们的C++更新循环返回到最初调用它的Java代码时。
如果你的应用程序开始在C++中执行,然后调用Java,我认为你永远不会有自动的本地引用垃圾收集,除非你再次从Java调用C++(调用堆栈:C++->Java->C++
),在这种情况下,当你返回Java时,你在最顶端的C++函数中所做的任何引用都将是GC’d(C++->Java->C++
->C++->Java
)。
实际上这里有一些详细的解释:
全球和本地参考
JNI将本机代码使用的对象引用分为两类:本地引用和全局引用。本地引用在本机方法调用期间有效,并且在本机法返回后自动释放。全局引用在显式释放之前保持有效。
对象作为本地引用传递给本机方法JNI函数返回的所有Java对象都是本地引用。JNI允许程序员从本地引用创建全局引用JNI函数期望Java对象同时接受全局和本地引用。本机方法可以返回对VM的本地或全局引用作为其结果。
在大多数情况下,程序员应该依靠VM在本机方法返回后释放所有本地引用。然而,有时程序员应该明确地释放本地引用。例如,考虑以下情况:
本机方法访问大型Java对象,从而创建对Java对象的本地引用。然后,本机方法在返回到调用者之前执行额外的计算。对大型Java对象的本地引用将防止该对象被垃圾收集,即使该对象在剩余的计算中不再使用。
本机方法创建大量的本地引用,尽管并非所有本地引用都同时使用。由于虚拟机需要一定的空间来跟踪本地引用,因此创建过多的本地引用可能会导致系统内存不足。例如,本机方法循环遍历一个大型对象数组,将元素检索为本地引用,并在每次迭代中对一个元素进行操作。在每次迭代之后,程序员不再需要对数组元素的本地引用。
JNI允许程序员在本机方法中的任何时候手动删除本地引用。为了确保程序员可以手动释放本地引用,不允许JNI函数创建额外的本地引用,除非它们作为结果返回引用。
本地引用仅在创建它们的线程中有效。本机代码不能将本地引用从一个线程传递到另一个线程。
- 如何返回对象C++的数组
- 如何使用std::min和std::less返回对象
- 如何通过引用返回对象
- 如何安全地从 DLL 调用返回对象
- 如何在不销毁对象的情况下返回对象列表
- 什么更好?返回对象指针列表?或返回指向对象列表的指针?
- 使用返回对象的函数处理错误
- 何时返回指针与返回对象的一般经验法则?
- 如何使用运算符+重载函数正确返回对象?
- C++,class,一个返回对象的函数
- 运算符的返回对象 = C++ 中的重载
- 从队列返回对象的最快方法,但前提是队列有它
- 如何使用条件表达式返回对象指针?
- 使用构造函数从函数返回对象
- 隐式转换函数的返回对象时是否会影响性能?
- 返回对象时从'const DList<int>* const'到 'DList<int>*' [-fallowive] 的转换无效
- 按值和堆栈大小限制返回对象
- 我应该如何从函数返回对象?
- c++:何时传递指针与返回对象
- 返回对象会丢失属性