导致OutOfMemoryError的Java JIT编译器

时间:2010-08-11 04:52:11

标签: java jvm jit

我们最近开始的一个应用程序偶尔会崩溃,并显示一条消息“java.lang.OutOfMemoryError:Chunk :: new请求8589934608个字节。交换空间之外?”。

我在网上四处看看,到处都有建议

  • 恢复为以前版本的Java
  • 摆弄内存设置
  • 使用客户端而非服务器模式

恢复到以前的版本意味着新的Java有一个bug,但我没有看到任何迹象。记忆根本不是问题;服务器有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)之后编译方法,以强制它几乎立即编译方法而不是在当天的随机点编译?
  3. @StephenC

    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, ...]
    3. jstack中提到的方法总是相同的,是我们写的。如果您查看示例jstack输出,您将知道我的意思,但由于显而易见的原因,我无法提供代码示例或文件名。我会说这是一个非常简单的方法。基本上是一些空检查,2个用于执行相等性检查并可能分配值的循环,以及之后的一些简单方法调用。总而言之,可能有40行代码。

      此问题在2周内发生了2次,但应用程序每天运行并每天重新启动。此外,这些应用程序在任何时候都没有处于高负荷状态。

3 个答案:

答案 0 :(得分:5)

您可以通过创建名为.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进程。

答案 1 :(得分:1)

好的,我做了一个快速搜索,在sun java forums that discusses找到了一个帖子。希望它有所帮助。

答案 2 :(得分:1)

这是另一个entry on Oracles forum。类似的零星崩溃。有一个答案是通过重新配置gc幸存者比率来解决问题。