当前位置: 首页 > 知识库问答 >
问题:

垃圾收集和JNI调用

梁承恩
2023-03-14

我遇到了一个JNI程序随机内存不足的问题。

这是一个32位java程序,它读取文件,进行一些图像处理,通常使用250MB到1GB。然后丢弃所有这些对象,然后程序对通常需要100-250MB的JNI程序进行一系列调用。

当交互运行时,我从未见过问题。但是,当对许多文件连续运行批处理操作时,JNI程序将随机运行内存溢出。它可能对一个或两个文件有内存问题,然后对下一个10个文件运行正常,然后再次出现故障。

在JNI调用之前,我已经转储了大量的可用内存,这些内存到处都是,有时是100MB,有时是800MB。我的解释是,Java垃圾收集有时在图像处理之后立即运行,有时不运行。如果不是,那么JNI程序可能没有足够的内存。

我已经阅读了所有关于GC是非确定性的、不应该调用它、不会产生任何影响等等的内容。但是在开始JNI调用之前强制GC似乎可以改善这种情况。

但是有没有办法真正确保在继续之前有一定量的空闲内存呢?

为了回答关于另一家公司提供的JNI程序的问题,我对它如何分配内存没有真正的了解。我只知道它是用c语言编写的,它没有垃圾收集功能。有人告诉我它需要100-250MB的内存,我看到的数字可以证实这一点。

也许我应该把这个问题改写为:如果我要进行一个JNI调用,我知道它需要250MB的内存,我如何保证它会有那么多的可用存储器?

当然,一个可能的解决方案是进行64位构建。然而,这个批处理操作是32位构建的QA的一部分,所以我想测试真实的东西。

共有3个答案

华烈
2023-03-14

FWIW(我意识到这是一种异端邪说)增加了对

System.gc();

在对每个文件进行第一次JNI调用之前,对这种情况进行了重大改进。20%的文件没有出现内存错误,现在的内存错误率不到5%。更好的是,这些错误不再是随机的,而是可以从一次运行到另一次运行重复出现,因此可以推测它们可以被跟踪。

康鹏云
2023-03-14

以下假设您正在使用hotspot jvm。

32位进程不仅受提交内存的约束,更重要的是,它们受虚拟内存(即保留地址空间)的约束。在64位系统上只能使用4GB的地址,而在32位系统上只能使用2-3GB的地址。

JVM将预先为托管堆保留一个固定的、可能很大的地址空间,然后在该空间的基础上动态分配一些内部结构,然后可能为DirectByteBuffers或内存映射文件分配更多的地址空间。这会给本机代码留下很少的运行空间。

使用本机内存跟踪来确定JVM的各个部分使用了多少和pmap

或者,您可以生成一个新进程并在那里进行图像处理。

华乐逸
2023-03-14

我自己解决这个问题的方法就是调用系统。gc(),但从本机代码内部:

#include <jni.h>
// ...
int my_native_function(JNIEnv* env, jobject obj) {
    jclass    systemClass    = nullptr;
    jmethodID systemGCMethod = nullptr;
    // ...
    // Take out the trash.
    systemClass    = env->FindClass("java/lang/System");
    systemGCMethod = env->GetStaticMethodID(systemClass, "gc", "()V");
    env->CallStaticVoidMethod(systemClass, systemGCMethod);
}

我希望这对你也有用。

 类似资料:
  • 问题内容: 是否有可能使Go中的垃圾收集器处理并释放通过C代码分配的内存?抱歉,我之前没有使用过C和cgo,因此我的示例可能需要澄清。 假设您有一些要使用的C库,并且该库分配了一些需要手动释放的内存。我想做的是这样的: 当Go运行时中没有对* Stuff的引用时,垃圾收集器是否可以调用Stuff.Free()? 我在这里有意义吗? 也许更直接的问题是:是否有可能通过编写一个在该对象的引用为零时运行

  • Kubernetes 垃圾收集器的角色是删除指定的对象,这些对象曾经有但以后不再拥有 Owner 了。 注意:垃圾收集是 beta 特性,在 Kubernetes 1.4 及以上版本默认启用。 Owner 和 Dependent 一些 Kubernetes 对象是其它一些的 Owner。例如,一个 ReplicaSet 是一组 Pod 的 Owner。具有 Owner 的对象被称为是 Owner

  • 本文向大家介绍Java垃圾收集,包括了Java垃圾收集的使用技巧和注意事项,需要的朋友参考一下 示例 C ++方法-新增和删除 在像C ++这样的语言中,应用程序负责管理动态分配的内存所使用的内存。当使用new运算符在C ++堆中创建对象时,需要相应地使用delete运算符来处置该对象: 如果程序忘记了delete一个对象而只是“忘记”了该对象,则关联的内存将丢失给应用程序。这种情况的术语是内存泄

  • JavaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。 而在C 和C++之类的语言中,开发人员的一项基本任务就是手工跟踪内存的使用情况,这是造成许多问题的一个根源。在编写JavaScript 程序时,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理。这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其

  • 我正在使用JCUDA,想知道JNI对象是否足够聪明,可以在垃圾收集时解除分配?我能理解为什么这可能在所有情况下都不起作用,但我知道它会在我的情况下起作用,所以我的后续问题是:我如何才能完成这一点?有没有我可以设置的“模式”?我需要构建抽象层吗?或者答案真的是“不,永远不要尝试”,那么为什么不呢? 编辑:我只是指通过JNI创建的本机对象,而不是Java对象。我知道所有Java对象都被平等地对待,即垃

  • 问题内容: 我想向JVM注册一个回调,所以我知道何时进行垃圾回收。有什么办法吗? 编辑:我想这样做,以便可以在应用程序日志中发生垃圾收集时注销,这样我就可以查看它是否与我所看到的问题相关。启用- Xloggc很有帮助,但是将GC日志中的时间(自应用程序启动以来使用秒数)整合到我的主应用程序日志中有点棘手。 编辑2012年4月:从Java7u4开始,您可以从GarbageCollectorMXBea