我有一个包含短字符串列表的二进制文件,它在启动时加载并作为从字符串到protobuf(包含字符串......)的映射存储在内存中。 (不理想,但由于遗留问题很难改变设计) 最近,该列表从大约2M增加到大约20M,导致它在构建地图时失败。
首先我得到OutOfMemoryError: Java heap space
。
当我使用xms和xmx增加堆大小时,我们遇到了GC overhead limit exceeded
。
在具有15GB可用内存和以下JVM args的Linux 64位计算机上运行(我增加了RAM 10G-> 15G,堆标志6000M - > 9000M):
-Xms9000M -Xmx9000M -XX:PermSize=512m -XX:MaxPermSize=2018m
这个二进制文件做了很多事情,并且正在为实时流量提供服务,因此我无法承受偶尔被卡住的情况。
编辑:我最终去做了显而易见的事情,即修复代码(从HashMap更改为ImmutableSet)并添加更多RAM(-Xmx11000M)。
答案 0 :(得分:2)
我正在寻找一个临时解决方案,如果可行的话,我们可以使用更具可扩展性的解决方案。
首先,您需要弄清楚“OOME:GC开销限制是否超出”是由于堆是:
太小......导致JVM重复执行完整的GC,或
太大......导致JVM在运行Full GC时抖动虚拟内存。
您应该能够通过打开和检查GC日志来区分这两种情况,并使用操作系统级别的监视工具来检查过多的分页负载。 (检查分页级别时,还要检查问题是否是由于JVM与另一个需要大量内存的应用程序之间的RAM竞争造成的。)
如果堆太小,请尝试将其放大。如果太大,请将其缩小。如果你的系统出现两种症状......那你就有一个大问题。
您还应该检查是否为您的JVM启用了“压缩oops”,因为这会减少JVM的内存占用。 -XshowSettings
选项列出了JVM启动时生效的设置。如果禁用压缩oops,请使用-XX:+UseCompressedOops
启用压缩oops。
(您可能会发现默认情况下启用了压缩的oops,但值得检查。这将是一个简单的修复...)
如果上述方法都不奏效,那么您唯一的快速解决方法就是获得更多内存。
但显然,真正的解决方案是重新设计代码,以便您不需要大量(并且随着时间的推移)内存中的数据结构。