10

我正在运行javajava -Xmx240g mypackage.myClass

操作系统是 Ubuntu 12.10。

topMiB Mem 245743 total,并表明 java 进程virt 254g从一开始就有,并且res正在稳步增长到169g. 那时它看起来好像开始了很多垃圾收集,我认为是因为该程序当时是单线程的,并且CPU%大部分100%时间都到了这一点,并且此时它在 1300-2000 左右跳跃(我的结论是多线程垃圾收集器),然后res慢慢移动到172g. 那时java崩溃了

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

在与new double[2000][5]

java -version

java version "1.7.0_15" OpenJDK Runtime Environment (IcedTea7 2.3.7) (7u15-2.3.7-0ubuntu1~12.10) OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

硬件是 Amazon cr1.8xlarge 实例

在我看来,即使有大量可用内存,java 也会崩溃。这显然是不可能的,我必须把一些数字解释错。我应该在哪里查看以了解发生了什么?

编辑:

我没有指定任何 GC 选项。唯一的命令行选项是-Xmx240g

我的程序成功地处理了许多输入,并且top有时说它使用了高达 98.3% 的内存。但是,我通过某些程序输入重现了上述情况。

编辑2:

这是科学应用。它有巨大的树(1-10 百万个节点),在每个节点中有几个double大小约为的数组。300x3 - 900x5。初始树创建程序后不会分配太多内存。大多数时候,这些数组都会进行一些算术运算。

编辑3:

HotSpot JVM 以同样的方式死机,在 170-172g 标记处大量使用 CPU,并因同样的错误而崩溃。看起来 70-75% 的内存是 JVM 不想跨越的一条神奇线。

最终解决方案:使用 -XX:+UseConcMarkSweepGC -XX:NewRatio=12 程序通过了 170g 标记并且很高兴地进一步工作。

4

3 回答 3

9

分析

您需要做的第一件事是获取堆转储,这样您就可以准确地确定 JVM 崩溃时堆的样子。将这组标志添加到命令行:

-XX:+HeapDumpOnOutOfMemoryError -verbose:gc -XX:+PrintGCDetails

当发生崩溃时,JVM 会将堆写入磁盘。坦率地说,在这么大的堆上需要很长时间。如果您已经在运行 Eclipse,请下载Eclipse MAT或安装插件。从那里,您可以加载堆转储并运行几个罐头报告。您需要检查 Leak Suspects 和 Dominator Tree 以查看内存的去向并确定您没有实际的泄漏。

之后,我建议您阅读Oracle 的有关垃圾收集的文档,但是您可以考虑以下几点:

并发 GC

-XX:+UseConcMarkSweepGC 

我从未听说有人在这么大的堆上使用仅并行收集器而侥幸。您可以激活并发收集器,并且您需要阅读增量模式并确定它是否适合您的工作负载/硬件组合。

无堆比

-XX:MinHeapFreeRatio=25

当您进行完整收集时,将其调低以降低垃圾收集器的标准。这可能会阻止您在执行完整收集时耗尽内存。40% 是默认值,尝试使用较小的值。

新比率

-XX:NewRatio

我们需要更多地了解您的实际工作量:这是一个 web 应用程序吗?一个摇摆应用程序?取决于对象在堆上保持活动的时间长短,将对新的比率值产生影响。默认情况下,像您正在运行的服务器模式 VM 具有相当高的新比率 (8:1),如果您有很多长寿命对象,这可能不适合您。

于 2013-04-19T01:38:03.627 回答
1

作为一般建议,永远不要使用 OpenJDK,更不用说用于生产环境,它比 Sun/Oracle 的慢得多。

除此之外,我从未见过 VM 使用这么多内存,但我想这就是您需要的(或者您的代码使用的内存比需要的多?)

编辑:用于服务器的 OpenJDK 很好,与 Sun/Oracle JDK 的唯一区别在于桌面内容(声音、gui ...),所以忽略那部分。

于 2013-04-19T01:03:08.177 回答
1

如果我正确理解了您的问题,那么看起来内存泄漏实际上是在程序运行之前发生的new double[2000][5]。似乎在命中该行时内存已经很低,因此当该行要求更多内存时它会抛出。

我会使用 jvisualvm 或类似工具来找出内存泄漏的位置。我遇到的内存泄漏主要与在循环中创建字符串、未清除缓存等有关。

于 2013-04-19T01:07:28.253 回答