Java JIT 编译器导致 OutOfMemoryError

2023-11-24

我们最近开始偶尔崩溃的一个应用程序,并显示一条有关“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 请求都发生了错误。在任何时候,发生这种情况时编译的方法都是相同的。它是一种简单的方法,没有嵌套循环,没有递归,并且在直接返回静态成员字段或实例成员字段的对象上使用方法,计算量很少。

所以我有两个问题:

  1. 有人有什么建议吗?
  2. 我可以测试在测试环境上编译此特定方法是否存在问题,而无需运行整个应用程序,直接调用 JIT 编译器吗?或者我应该启动应用程序并告诉它在更小的调用次数(例如 2)之后编译方法,以强制它几乎立即编译方法,而不是在一天中的随机点编译方法?

@史蒂芬C

JVM 是 1.6.0_20(以前是 1.6.0_0),在 Solaris 上运行。我知道由于几个原因,编译导致了问题。

  1. ps在它显示之前的几秒内,ID 与编译器线程(来自 jstack)相对应的 java 线程正在占用 100% 的 CPU 时间
  2. 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(使用前将#替换为@)

Java JIT 编译器导致 OutOfMemoryError 的相关文章

随机推荐