记录一次Java内存溢出问题

现象:

本地开发环境Eclipse测试导出某张表的数据到Excel,报堆溢出:java.lang.OutOfMemoryError: Java heap space。但是测试环境或者开发环境启动Tomcat的时候配置-Xmx参数后就不报错。

分析流程:

先加入-Xmx参数调大堆内存到1G,测试不报错。用jdk\bin\jvisualvm查看内存情况,发现导出此表需要占用200M以上堆内存空间。

怀疑是默认堆最大内存,也就是不加-Xmx参数时可分配的最大堆内存不足,google一番,没有任何结果,包括官方文档,没有找到关于-Xmx参数默认值的说明。StackOverflow也木有啊。到SegmentFault去问了一下,无非是启动的时候打印看一下。

网上普遍介绍一个参数,-XX:+PrintFlagsFinal可以查看启动JVM时的配置值。加入此参数,报Unrecognized VM option ‘+PrintFlagsFinal’,eclipse中或者CMD中运行都会报这个错误,不支持的参数。再经过一番谷歌,有人指出这个参数是1.6.0.21之后才有的。我看了一下IDE自带的JRE是1.6.0.16。

我本机是安装了1.6.0.43的,将本地安装的jdk加入到eclipse已安装JRE中。用43版本的jre启动tomcat,加入-XX:+PrintFlagsFinal参数,发现最大堆内存是2G左右(本机8G内存),导出也没有内存溢出,瞬间懵逼。

不能用PrintFlagsFinal看最大内存,怎么办。用javaagent参数,写个JavaAgent程序,在启动tomcat之前执行。具体方法一搜一大堆。

public class MemoryAgent {
public static void premain(String agentOps, Instrumentation inst) {
System.out.println(“=========== MemoryAgent ===========”);
Long max = Runtime.getRuntime().maxMemory();
Long total = Runtime.getRuntime().totalMemory();
Long free = Runtime.getRuntime().freeMemory();
System.out.println(“=========== MAX :”+max);
System.out.println(“=========== TOTAL:”+total);
System.out.println(“=========== FREE :”+free);
}
}

果然最大堆内存是64M。

另外还有一个方法,jvisualvm也可以看到最大堆内存的值。

总结:

1.6.0.16在没有配置-Xmx标签的时候,默认最大堆内存是64M.

1.6.0.43在没有配置-Xmx标签的时候,默认最大堆内存是物理内存的1/4.

解决办法:

1、启动参数加入-Xmx并配置较大的值

2、升级JDK到1.6最大小版本或者更高大版本

3、启动参数加入-server。但是此参数会增加应用启动时间,但是会提高运行时效率,建议开发环境启用。

 

版权声明:除标明转载的文章外皆为原创文章
转载请注明: 转载自Liudroid的博客,作者:Liudroid
本文链接地址: 记录一次Java内存溢出问题

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注