2010-08-11 74 views
9

我们最近开始偶尔使用有关“java.lang.OutOfMemoryError:请求8589934608字节的Chunk :: new。Out of swap space?”消息开始崩溃的应用程序。Java JIT编译器导致OutOfMemoryError

我环顾四周,在网络上,到处都建议只限于

  • 恢复到以前的版本的Java
  • 小提琴与内存设置
  • 使用客户端而不是服务器模式

恢复到以前的版本意味着新的Java有一个错误,但我没有看到任何迹象。记忆根本不是问题;服务器有32GB可用,并且Xmx设置为20,而Xms是10.我看不到剩余12GB的JVM耗尽(减少给予机器上其他几个进程的量)。由于应用程序和环境的特性,我们坚持使用服务器模式。

当我查看应用程序的内存和CPU使用情况时,我发现整天的内存使用量不断增加,但在使用之前突然发生CPU使用率高达100%,内存使用量从X增加到X + 2GB,到X + 4GB,到(有时)X + 8GB,到JVM死亡。这似乎是在JIT编译中可能发生循环重复数组大小调整。

我现在看到上述8GB请求和16GB请求发生错误。所有时候,这种情况发生时编译的方法都是一样的。这是一个简单的方法,它具有非嵌套循环,没有递归,并且使用方法直接返回静态成员字段或实例成员字段,计算量很少。

所以我有2个问题:

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

@StephenC

JVM是1.6.0_20(先前1.6.0_0),在Solaris运行。我知道这是由于几个原因导致问题的汇编。

  1. 在导致它的秒ps示出与对应于编译器线程(从jstack)ID的Java线程占用了100%的CPU时间
  2. jstack示出了问题是JavaThread "CompilerThread1" daemon [_thread_in_native, id=34, ...]

jstack中提到的方法总是一样的,而且是我们写的。如果您看到示例jstack输出,您将知道我的意思,但出于显而易见的原因,我无法提供代码示例或文件名。我会说这是一个非常简单的方法。 Essentiall少数空检查,2 for循环进行平等检查并可能分配值,以及一些简单的方法调用之后。总共可能有40行代码。

尽管应用程序每天运行并且每天都重新启动,但该问题在两周内发生过两次。此外,这些应用程序在这些时间都没有承受重负。

+0

如果您说出您正在使用的JVM版本和补丁级别(以及之前的内容)以及您的操作系统/硬件平台是什么,这将会很有帮助。另外,为什么你在JIT编译期间得出结论:问题是如何发生的,你如何计算出正在编译的方法......以及方法的代码是什么样的。 – 2010-08-11 08:59:28

+0

您是否找到满意的解决方案? – 2015-01-01 17:48:00

+0

对不起*非常*迟到的回复 - 我已经标记了答案 – Phil 2015-03-15 12:06:03

回答

1

好吧,我做了一个快速搜索,发现了一个关于sun java的线程forums that discusses这个。希望能帮助到你。

+0

是的,我也看到了。他的问题是与单个分配中剩余的记忆相冲突。我看到多个数组resizings不应该有的地方。编译一个方法没有理由需要16GB的内存,对吧? – Phil 2010-08-11 05:31:44

+0

然后,你也可能尝试了你在你的问题中提到的建议。这些工作是否有用? – naikus 2010-08-11 06:09:34

1

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

5

通过创建名为.hotspot_compiler的文件并将其放入应用程序的工作目录中,可以排除特定的方法被JIT处理。只需按以下格式在文件中添加一个条目:

exclude com/amir/SomeClass someMethod 

而且从编译器的控制台输出将类似于:

### Excluding compile: com.amir.SomeClasst::someMethod 

欲了解更多信息,请阅读this。如果你不知道你的应用程序“工作目录”,在您的Java启动脚本或命令行使用

-XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler 

。或者,如果您不确定它的JIT编译器是否有错误,并且希望查看是否可以在没有任何JIT的情况下重现此问题,请使用-Xint运行Java进程。