在 Mac OSX 5.8 上,我有一个 Java 程序以 100% 的 CPU 运行了很长时间——几天或更长时间(它是一个分析并发程序的模型检查器,所以这或多或少是意料之中的)。然而,它的虚拟内存大小(如 OSX 的 Activity 监视器中所示)在大约一天后变得巨大:现在是 16GB 并且还在增加。物理内存使用量大致稳定在 1.1GB 左右。
我想知道:16GB(并且还在不断增加)是否表明可能会减慢我的程序的问题?
I start the program with "java -Xmx1024m -ea"
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07-334-9M3326)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02-334, mixed mode)
感谢大家的建议。我将尝试一些答案中给出的分析建议,然后回来(由于运行时间多天,这可能需要一段时间)。
为了回答下面的一些问题,模型检查器几乎不执行任何 I/O(仅打印语句,具体取决于调试设置)。在我使用的模式下,它没有 GUI。我不是模型检查器的主要作者(尽管我研究过它的一些内部结构),但我不认为它使用了 JNI。[<--- 编辑:这是错误的,详情如下]不做任何内存映射。此外,我并没有要求 Oracle/Sun 的 JVM 创建大量线程(请参阅下面的解释)。
额外的虚拟内存并没有导致模型检查器死掉,但是根据打印输出的频率,它会随着虚拟内存使用量的增加而逐渐运行得越来越慢。 (不过,也许这只是因为越来越多的垃圾收集。)我计划周一在 Windows 机器上尝试一下,看看是否会出现同样的问题。
一点额外的解释:我正在运行的模型检查器 (JPF) 本身就是一个几乎完整的 JVM(完全用 Java 编写),它在 Oracle/Sun 的 JVM 下运行。当然,作为一个虚拟机,JPF 非常专业地支持模型检查。
这有点违反直觉,但这意味着即使我正在模型检查的程序设计为多线程,但就 Sun 的 JVM 而言,只有一个线程:运行 JPF 的线程。 JPF 模拟我的程序需要的线程作为其模型检查过程的一部分。
我相信 Stephen C 已经指出了问题; Roland Illig 给了我验证它的工具。我对 JNI 的使用是错误的。 JPF 本身不使用 JNI,但它允许使用插件,并且 JNI 被配置的插件之一使用。幸运的是,我可以使用纯 Java 的等效插件。初步使用其中一个显示在过去几个小时内虚拟内存没有增长。感谢大家的帮助。
最佳答案
我怀疑这也是一个泄漏。但这不可能是“正常”内存泄漏,因为 -Xmx1024m 选项正在限制正常堆。同样,它不会是“permgen”堆的泄漏,因为 permgen 的默认最大大小很小。
所以我怀疑是以下情况之一:
您正在泄漏线程;即线程正在创建但没有终止。它们可能不活跃,但每个线程都有一个未在常规堆中分配的堆栈段(默认情况下为 256k 到 1Mb ... 取决于平台)。
您正在泄露直接映射文件。这些被映射到操作系统在常规堆之外分配的内存段。 (@bestsss 建议您查找泄漏的 ZIP 文件句柄,我认为这是其中的一个子案例。)
您正在使用一些泄漏 malloc 内存或类似代码的 JNI/JNA 代码。
无论哪种方式,内存分析器都可能隔离问题,或者至少消除一些可能性。
JVM 内存泄漏也是一种可能性,但在您明确消除您自己的代码和正在使用的库/应用程序中的可能原因之前,开始怀疑 JVM 是不明智的。
关于具有 16GB 虚拟内存且不断增长的 Java 程序 : is it a problem?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6240985/