JNI错误: 本地引用表溢出512个条目

18

我的函数如下所示。它被执行了多次。在某个时刻,当 jobject nvarObject = env->GetObjectField (var1, nvar1) 执行时,它会崩溃,并出现 JNI 错误: Local reference table overflow 512 entries.

有谁能够查看一下这个问题并提供一些帮助呢?


我不确定什么时候应该清理本地引用。我正在尝试使用 (*env)->DeleteLocalRef( env, cls ) 清理本地引用,但问题仍然存在。 - rvp
有没有出现导致函数提前返回的错误?如果是这样,您将永远不会触发DeleteLocalRef()代码。确保在从该函数返回之前清除引用,特别是在被循环调用多次之前返回控制权给JVM。 - Jason LeBrun
是的,这个函数被执行了很多次,然后在某个时候它会一直执行到 jobject nplpidObject = env->GetObjectField (param, nplpids); 这一行代码,然后就会崩溃并报告溢出错误。 - rvp
1
啊,是的。GetObjectField 也会返回一个引用(任何 Java 对象都将是一个引用)。因此,在退出函数之前,您应该删除该引用。 - Jason LeBrun
1个回答

24

所有返回 jobject 或类似对象引用的JNI方法都会在引用表中创建本地引用。当你将控制权返回给JVM时,这些引用会自动清理,但如果你正在创建许多引用(例如,在循环中),则需要手动清理它们。

通过在 cls 引用上调用 DeleteLocalRef,你已经做得很好了,但请注意,GetObjectField 也返回一个 jobject,因此在退出函数之前应该删除其中返回的引用。

还要确保在从错误条件返回之前清理任何现有的引用!

另一种方法是:在调用循环中的函数顶部,调用 PushLocalFrame(env, 5),并在函数中任何返回的位置之前调用 PopLocalFrame(env)。这将自动清理在该函数调用期间创建的所有引用。第二个参数是帧中您想要的本地引用数——如果在函数执行期间需要超过5个本地引用,请使用比5更高的值。


2
另一个方便的方法是使用PushLocalFrame/PopLocalFrame。当您调用PopLocalFrame时,最后一次调用PushLocalFrame之后创建的本地引用将被删除。这比跟踪创建本地引用的所有位置更方便。 - Jason LeBrun
2
我赞同这个观点 - Push/PopLocalFrame 很容易使用且始终有效(并且可以用 C++ RAII 进行封装),而手动确定所有引用创建的位置则很困难且本质上容易出错。 - Alan Stokes
已经为jobject执行了DeleteLocalRef。但是仍然会崩溃……为了使用PushLocalFrame(env,size),我不知道该函数内部会创建多少引用。有没有解决方法,或者我应该盲目地将大小设置为某个值…… - rvp
1
@rahulvenus 不管你传递什么大小,都没有太大的关系。如果成功了,你就可以保证能够创建那么多的引用 - 但通常创建比你要求的更多是没问题的,除非你完全耗尽了内存。 - Alan Stokes
2
512限制是从哪里来的? - Nathan H
显示剩余2条评论

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