首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有16 is虚拟内存并不断增长的Java程序:这是一个问题吗?

具有16 is虚拟内存并不断增长的Java程序:这是一个问题吗?
EN

Stack Overflow用户
提问于 2011-06-05 04:23:26
回答 6查看 7K关注 0票数 5

在MacOSX5.8上,我有一个在100% CPU上运行很长时间的Java程序--几天或更长时间(它是一个分析并发程序的模型检查器,所以这或多或少是预期的)。然而,它的虚拟内存大小,如OSX的Activity所示,在一天左右之后就变得巨大了:现在它只有16 in,而且还在增长。物理内存的使用大致稳定在1.1GB左右。

我想知道:16 my (而且还在增长)是否是一个问题的迹象,可能会减慢我的程序?

代码语言:javascript
复制
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已经指出了这个问题;Roland给了我验证这个问题的工具。我对JNI的使用错了。JPF本身不使用JNI,但它允许插件和JNI被配置的插件之一使用。幸运的是,我可以使用类似的插件,这些插件都是纯Java的。其中之一的初步使用显示,在过去的几个小时里,虚拟内存没有增长。感谢大家的帮助。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-06-05 05:47:12

我怀疑这也是个漏洞。但是它不可能是“正常”内存的泄漏,因为-Xmx1024m选项正在限制正常堆。同样,它不会是' permgen‘堆的泄漏,因为permgen的默认最大大小是小的。

因此,我怀疑这是以下其中之一:

  • 您正在泄漏线程;也就是说,正在创建线程,但没有终止。它们可能不是活动的,但是每个线程都有一个堆栈段(默认情况下是256 K到1Mb ).在常规堆中没有分配的(取决于平台)。
  • 您正在泄漏直接映射的文件。这些映射到常规堆之外的OS分配的内存段。(@bestsss建议您查找泄露的ZIP文件句柄,我认为这是其中的一个子案例。)
  • 您正在使用一些泄漏malloc‘’ed内存的JNI / JNA代码,或者类似的代码。

无论哪种方式,内存分析器都可能隔离问题,或者至少消除一些可能性。

JVM内存泄漏也是一种可能性,但在您自己使用的代码和库/应用程序中彻底消除了可能的原因之前,开始怀疑JVM是不明智的。

票数 11
EN

Stack Overflow用户

发布于 2011-06-05 05:57:34

由于您的应用程序不是实时应用程序,所以可以执行以下操作:

代码语言:javascript
复制
jps -v

从该表中获取进程id,并将其保存为pid

代码语言:javascript
复制
jmap -histo $pid > before-gc.hgr
jmap -histo:live $pid > after-gc.hgr
jstack -v $pid > threads.txt

threads.txt文件告诉您进程目前正在做什么。

堆使用直方图before-gc.hgrafter-gc.hgr告诉您一个完整的垃圾回收可以释放多少内存。

也许你会从中得到一些关于正在发生的事情的提示。

票数 3
EN

Stack Overflow用户

发布于 2011-06-05 05:02:23

完成对象后,您是否正确地对所有引用进行NULL处理?我想知道这是否是一个简单的内存泄漏。

我在C程序中看到了这种行为,这些程序为不同大小的对象混合了大量的分配和释放。您可以得到内存页的一半使用,但没有任何足够大的漏洞,可以用来满足新的内存请求。

这不仅会导致交换,而且会随着时间的推移破坏引用的局部性--交换会变得更糟。

C程序中的解决方案通常是切换到板坯分配器,并将不同大小的对象保存在不同的内存页上。不再有奇数大小的洞,而且总是有一个指向空间的指针,无论你的对象是什么,空间的大小都是合适的。

当然,在像Java这样的托管环境中这样做可能很困难。人们可能希望JVM已经在这样做了。(考虑到托管环境可以更新对新内存位置的引用并定期重新打包,即使是简单的内存分配方法也应该防止愚蠢的漏洞。)

有问题的迹象通常来自交换流量。如果您在您的系统上看到大量交换通信量,即使进程的RSS (驻留集大小)保持稳定,那么您可能要为看起来完全在内存中运行的操作执行大量的磁盘IO。在Linux和其他一些Unix系统上,您可以使用vmstat 1命令找到交换流量信息:

代码语言:javascript
复制
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 0  0      0 727392 351128 3846980    0    0    13    16   41   73  3  1 96  0
 0  0      0 727392 351128 3846988    0    0     0     0 1267 4742  5  1 95  0
...

siso列每秒显示块。(嗯,无论您在vmstat 1vmstat 2中选择了什么时间间隔,等等。)

如果交换流量很低,那么您可能没有什么可担心的。如果交换流量很高,那么一定要设法找出交换的原因。这需要更多的工作。:)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6240985

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档