我们最近开发的一个应用程序偶尔会崩溃,并显示“java.lang.OutOfMemoryError:requested 8589934608 bytes for Chunk :: new。是否已用完交换空间?”的消息。
我在网上搜索了一下,但建议都只限于:
1. 返回先前版本的Java 2. 修改内存设置 3. 使用客户端而不是服务器模式
返回先前版本的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)之后编译方法,以便迫使它几乎立即编译该方法,而不是在一天的随机时间点进行?
JVM是1.6.0_20(以前是1.6.0_0),运行在Solaris上。我知道编译是一个问题,因为:
1. 崩溃前几秒钟内的ps显示,具有与编译器线程相对应的Java线程(来自jstack)正在占用100%的CPU时间。 2. jstack显示问题出现在“CompilerThread1”守护程序[_thread_in_native,id = 34,...]中的JavaThread中。
这个问题在2周内发生了2次,尽管应用程序每天运行并且每天重新启动。此外,这些时间应用程序没有承受重负载。
我在网上搜索了一下,但建议都只限于:
1. 返回先前版本的Java 2. 修改内存设置 3. 使用客户端而不是服务器模式
返回先前版本的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)之后编译方法,以便迫使它几乎立即编译该方法,而不是在一天的随机时间点进行?
JVM是1.6.0_20(以前是1.6.0_0),运行在Solaris上。我知道编译是一个问题,因为:
1. 崩溃前几秒钟内的ps显示,具有与编译器线程相对应的Java线程(来自jstack)正在占用100%的CPU时间。 2. jstack显示问题出现在“CompilerThread1”守护程序[_thread_in_native,id = 34,...]中的JavaThread中。
jstack
中提到的方法始终相同,是我们编写的方法。如果您查看jstack
输出示例,您将知道我的意思,但由于明显的原因,我不能提供代码示例或文件名。我会说这是一个非常简单的方法。基本上是一些空值检查、两个循环进行等值检查并可能赋值,以及一些简单的方法调用。总共大约40行代码。这个问题在2周内发生了2次,尽管应用程序每天运行并且每天重新启动。此外,这些时间应用程序没有承受重负载。