我们最近启动的一个应用程序偶尔会崩溃,并显示有关“java.lang.OutOfMemoryError:为 Chunk::new 请求 8589934608 字节。交换空间不足?”的消息。
我在网上看了一圈,到处都是建议
- 恢复到以前的 Java 版本
- 摆弄内存设置
- 使用客户端而不是服务器模式
恢复到以前的版本意味着新的 Java 有一个错误,但我还没有看到任何迹象。内 stub 本不是问题;服务器有 32GB 可用空间,Xmx 设置为 20,而 Xms 为 10。我看不到 JVM 用完了剩余的 12GB(减去机器上少数其他进程的数量)。由于应用程序和环境的性质,我们坚持使用服务器模式。
当我查看应用程序的内存和 CPU 使用情况时,我看到一整天的内存使用情况都在持续,但就在它消失之前突然 CPU 使用情况上升到 100%,内存使用情况从 X 到 X + 2GB,到 X + 4GB,到(有时)X + 8GB,到 JVM 死亡。似乎在 JIT 编译中可能存在重复调整数组大小的循环。
我现在已经看到上述 8GB 请求和 16GB 请求都发生了错误。在任何时候,发生这种情况时编译的方法都是相同的。它是一个简单的方法,没有嵌套循环,没有递归,并且在对象上使用方法直接返回静态成员字段或实例成员字段,计算量很小。
所以我有两个问题:
- 有人有什么建议吗?
- 我可以测试在测试环境中编译此特定方法是否存在问题,而不运行整个应用程序,直接调用 JIT 编译器吗?或者我应该启动应用程序并告诉它在调用次数少得多(比如 2)后编译方法,以强制它几乎立即编译方法,而不是在一天中的随机时间点编译方法?
@StephenC
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
输出,您就会明白我的意思,但出于显而易见的原因,我无法提供代码示例或文件名。我会说这是一个非常简单的方法。 Essential 少量空值检查,2 个用于执行相等性检查并可能分配值的循环,以及之后的一些简单方法调用。总共可能有 40 行代码。
这个问题在 2 周内发生了 2 次,尽管应用程序每天都在运行并且每天都会重新启动。此外,应用程序在任何时候都没有承受重负载。
最佳答案
您可以通过创建一个名为 .hotspot_compiler
的文件来排除特定方法被 JIT 处理并将其放入您的应用程序“工作目录”中。只需按以下格式在文件中添加一个条目:
exclude com/amir/SomeClass someMethod
编译器的控制台输出如下:
### Excluding compile: com.amir.SomeClasst::someMethod
有关详细信息,请阅读 this .如果您不确定您的应用程序“工作目录”是什么,请使用
-XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler
在您的 Java 启动脚本或命令行中。
或者,如果您不确定它是 JIT 编译器的错误,并且想看看您是否可以在没有任何 JIT 的情况下重现该问题,请使用 -Xint
运行您的 Java 进程。 .
关于Java JIT 编译器导致 OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3455381/