为什么JNI全局引用有最大数量限制?

3
作为我们所知道的,JNI是Java和C++之间的桥梁。最近我正在编写一个Java项目,它的主要模块基于需要存储大量GlobalReference的C++。随着活动的开展,这个数量将增加。因此,GlobalReferences的最大数量(65535)成为一个严重的问题,我必须使用特殊的方法来解决这个问题。
所以我很感兴趣为什么GlobalReferences有限制。它只是用于检测内存泄漏吗像其他人说的那样

如果你需要甚至一些 GlobalReferences,那么你已经面临了一个重大问题。请重新考虑。 - user207421
很抱歉,EJP,我不太明白您的意思。在我的项目中,GlobalReferences的生命周期由C++对象管理,因此我必须保留大量的引用直到活动结束。为什么这是一个主要问题? - YXP
1
这是一个重大问题,因为你已经达到了限制。 - user207421
很晚才来参加,但有人知道一个官方资源声明JNI中的全局引用限制吗? - Paul Omta
64k的限制只是Android Java虚拟机的限制,没有普遍的限制。在Android上,甚至方法的数量曾经也有限制。 - Lothar
3个回答

5
很容易回答“为什么”的问题。Android JVM中的全局引用表(无论是Dalvik还是ART)具有有限的条目,因为它的架构师认为没有人需要更多。他们有不同的限制需要考虑:内存约束、性能、稳定性和维护工作。但毕竟,这更像是一个修辞问题,而对它的回答不如实用建议重要。随后是这些建议:
  • Android JVM中引用表的限制将会一直存在。不要期望在下一个Android版本中这些表会变得更大 (但也许其中一些会)

  • 无论未来的Android版本发生什么情况,当前版本都将会一直存在。数百万人 仍在使用2010年发布的Gingerbread版本的Android设备(20亿中的0.6%)。截至 今天, 超过20%的设备上有Dalvik JVM。

  • 如果你接近或达到了内部JVM表的限制,你必须重新考虑你的架构。即使它不是每次都发生,当这些表溢出时,你不能信任系统的行为。

  • 请记住,你的应用程序可用的内存也是有限的,你使用的越多,在多任务环境下你的应用程序就越容易受到性能影响:如果内核需要为其他应用程序提供内存,它随时可以杀掉你的应用程序。

  • 如果你在Java端聚合你的对象,你就可以避免表溢出。例如,你可以把成千上万个对象放入Java映射或数组中,并在C++中保持对集合的全局引用。你可以使用JNI访问 Map.put()Map.remove 来管理集合。


感谢您提供有用的建议! - YXP
1
这是Android版本的10k问题。在网络中,10k已经成为了一个10m的问题。我们有16GB的手机,但只能容纳65k个对象指针,换句话说,520k字节的指针?这在640k的内存限制下非常困难,有人曾说我们永远不需要更多。我们已经看到方法限制如何影响现实世界。 - Lothar

2

对于这个限制,有一个明显的解决方法,我目前也不得不使用它。只需声明一个对象数组,并使用该数组的索引。

在Java程序中,由于间接级别已经很高,建议优先使用数组而非向量。您可以分配更多的空间并自行管理数组中的空闲槽位,只需要几行简单的代码即可实现。


2
据我理解,这并不是真正检测内存泄漏的问题,而是关于整个内存管理的问题。(至于内存泄漏,显然,你不应该在本地代码中长时间保留Java对象,无论是全局引用还是非全局引用)。在大多数语言中,全局引用的使用有点反模式(当用其他方法可以解决问题时)。JNI的问题在于你的本地代码处于从属模式。JVM不能清理你在C代码中持有的东西,特别是全局引用(因为它们的生命周期是无限的),所以这些限制是为了防止开发人员滥用JNI而自讨苦吃。
此外,我有点好奇,你试图完成什么任务,需要存储超过65k个全局引用——我有一种感觉,你试图完成的任务允许采用不同的方法,一种不会使JNI超负荷的方法。
例如,现在我正在将一个本地数据库库连接到一个Android应用程序中,整个设置必须来回传递成千上万条数据库记录,即使是这种情况也有一个解决方案,即使是本地引用表(512个引用限制)也不会溢出,更不用说全局引用表了。
我知道可能已经太晚了,但如果你愿意分享你实际的任务,我们可能能够想出一个适当的处理方式。

我已经通过在Activity中传递String并在弹出新的Activity时释放该Activity中的所有GlobalReferences解决了这个问题。实际情况是,GlobalReferences由C++对象保留,从而将Java对象绑定到C++对象。简要地说,对于每个Android视图,都有一个C++节点作为控制器。 - YXP
JNI中的全局引用与其他语言中的全局引用完全没有关系。在JNI中,全局引用是一个指针,而在其他语言中,全局引用是全局变量。这绝对不是反模式。这个答案不应该被接受。它在很多方面都是错误的。Android/Java也可以被视为另一种表示层。真正的功能和业务逻辑应该在平台共享的独立C++代码中,而Java只是一小部分非常简单的函数。Ivan错误的观点是我们没有好的Android应用程序的原因。 - Lothar
需要超过65k的一个例子是文本编辑器,其中段落被保留为对象或可视化数据对象的图形编辑器。再次思考它只是指向GUI对象的指针(Android不过是在Linux之上的移动GUI)。 - Lothar

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