我们最近开始偶尔崩溃的一个应用程序,并显示一条有关“java.lang.OutOfMemoryError:为 Chunk::new 请求 8589934608 字节。交换空间不足?”的消息。
我在网上环顾四周,到处的建议都仅限于
- 恢复到以前的 Java 版本
- 摆弄内存设置
- 使用客户端而不是服务器模式
恢复到以前的版本意味着新的 Java 有错误,但我没有看到任何迹象。内存根本不是问题;服务器有 32GB 可用空间,Xmx 设置为 20,而 Xms 设置为 10。我看不到 JVM 耗尽了剩余的 12GB(减去分配给机器上少数其他进程的数量)。由于应用程序和环境的性质,我们只能使用服务器模式。
当我查看应用程序的内存和 CPU 使用情况时,我发现一整天的内存使用情况都是恒定的,但在它消失之前,CPU 使用情况突然上升到 100%,内存使用情况从 X 变为 X + 2GB,到 X + 4GB,到(有时)X + 8GB,到 JVM 死亡。看来 JIT 编译中可能存在重复数组大小调整的循环。
我现在看到上述 8GB 请求和 16GB 请求都发生了错误。在任何时候,发生这种情况时编译的方法都是相同的。它是一种简单的方法,没有嵌套循环,没有递归,并且在直接返回静态成员字段或实例成员字段的对象上使用方法,计算量很少。
所以我有两个问题:
- 有人有什么建议吗?
- 我可以测试在测试环境上编译此特定方法是否存在问题,而无需运行整个应用程序,直接调用 JIT 编译器吗?或者我应该启动应用程序并告诉它在更小的调用次数(例如 2)之后编译方法,以强制它几乎立即编译方法,而不是在一天中的随机点编译方法?
@史蒂芬C
JVM 是 1.6.0_20(以前是 1.6.0_0),在 Solaris 上运行。我知道由于几个原因,编译导致了问题。
-
ps
在它显示之前的几秒内,ID 与编译器线程(来自 jstack)相对应的 java 线程正在占用 100% 的 CPU 时间
-
jstack
显示问题出在JavaThread "CompilerThread1" daemon [_thread_in_native, id=34, ...]
中提到的方法jstack
总是同一个,并且是我们写的。如果你看样本jstack
输出你就会知道我的意思,但由于显而易见的原因,我无法提供代码示例或文件名。我会说这是一个非常简单的方法。本质上是一些空检查、2 个进行相等检查并可能赋值的 for 循环,以及之后的一些简单方法调用。总共可能有 40 行代码。
尽管应用程序每天运行并每天重新启动,但此问题在两周内发生了 2 次。此外,应用程序在任何时候都没有处于重负载状态。
您可以通过创建一个名为的文件来排除特定方法的 JIT 编译.hotspot_compiler
并将其放入应用程序的“工作目录”中。只需按以下格式在文件中添加一个条目:
exclude com/amir/SomeClass someMethod
编译器的控制台输出将如下所示:
### Excluding compile: com.amir.SomeClasst::someMethod
欲了解更多信息,请阅读this。如果您不确定应用程序的“工作目录”是什么,请使用
-XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler
在 Java 启动脚本或命令行中。
或者,如果您不确定是否是 JIT 编译器的错误,并且想看看是否可以在没有任何 JIT 的情况下重现问题,请使用以下命令运行您的 Java 进程-Xint
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)