遭遇OutOfMemoryError

来源:互联网 发布:网络棋牌输赢原理 编辑:程序博客网 时间:2024/04/25 12:42

这几天,网店系统基础架构进行了一次大的升级,升级之后例行的进行了压力测试,以前几次大的项目发布压力测试都没有任何问题,没想到这次出事故啦,而且是内存泄露?

系统运行环境:
硬件:Intel(R) Xeon(R) CPU 2.0G、4G RAM、Linux 2.6.9-42.ELsmp #1 SMP
软件:jboss-4.0.5.GA [Java HotSpot(TM) Server VM (build 1.5.0_10-b03, mixed mode)]
JAVA运行参数-server -Xms2048m -Xmx2048m -XX:NewSize=768m -XX:PermSize=128m -XX:MaxPermSize=128m

现象是这样的:
对系统压力测试大约4个小时左右,系统突然down掉,抛错为java.lang.OutOfMemoryError: requested 12 bytes for intptr_t in /BUILD_AREA/jdk1.5.0_10/hotspot/src/share/vm/runtime/deoptimization.cpp. Out of swap space?
由于是晚上进行,所以没有观察到任何比较奇怪的现象出现,再次压力测试,仍然抛错,但稍微有些不同 java.lang.OutOfMemoryError: requested 32756 bytes for ChunkPool::allocate. Out of swap space?
经多次压力,现象100%可以重现;

解决过程:
1、use jvmstat first
这是SUN自己的性能跟踪工具,他占用server资源很少;监控的结果令我们失望,因为JVM表现完全正常,我们分配的2G内存还有很多剩余,并没有耗尽;GC也很正常,没有出现明显的Full GC或者是每次GC时间太长的情况;
用top命令查看占用内存不到3G,也还算富裕;而且系统并没有JNI的使用;为什么会报OutOfMemoryError呢?未果!
2、search Out of swap space
更多都是遭遇了相同的问题,但是好像都没有一个很可行的解决办法,甚至有人怀疑是JDK的bug,也有人说可以用-Xss参数设置stack size大小,ss默认大小为512k,但是从监控上看我们的进程也没有那么多,但还是尝试了一把,再次压力问题仍然未解决!
3、try to see heap dump
添加参数-XX:+HeapDumpOnOutOfMemoryError,让系统出现OutOfMemoryError时将当时JVM内所有heap dump出来,使用jHAT分析;
很可惜,1.5中对该参数的支持超级有限,记录下来的信息很少,并没有我们想象的那么多,那么有用,基本上这些信息是无用的;再次失败!
4、back to OutOfMemoryError
由 于jvmstat 能看见的JVM内部信息有限,所以我们打算用专业工具JProfiler来进行详查;环境搞定之后,再次压力,不到2小时情况就重现了,但是从 JProfiler中观察到的信息显示JVM内部的确没有任何异常,结论和Jconsole观察后完全一样,JVM内部没有任何问题!但为什么会有此错 误?想不通……
5、focus on java heap with linux
再次search了linux环境下面java heap的相关工作原理及组成信息,有发现了!
其实java heap由2部分组成:其一为我们熟悉的JVM heap,其二为和OS相关的Native heap;
JVM heap完全由GC掌控,我们可以通过参数-Xms、-Xmx指定其大小,并且可以用工具对其进行监控;他管理的东西就是我们所有的Java Object;
而 Native heap是平台相关的,我们既不能设置其使用大小也不能干预他的使用状态;他管理的东西一般都是很底层的,比如JIT使用的buffer、GC的底层 data structures、JNI调用的所有相关对象、SWING/AWT调用需要的buffer和data structures……
由此想到,是否我们分配的JVM heap太大了,于是设置参数变为-Xms1536m -Xmx1536m再次压力,问题解决了!!!

虽然问题解决了,但是我们还是没能从根本上解释此次故障,因为系统可用的内存还有很多,并没有耗尽?
难道32位的JAVA所能操作的内存只有2G?JVM heap全部占完了会导致Native heap无法allocate memory?后续还需要进一步研究此事;

PS:
1、上面我们提到专业级的性能监控工具JProfiler,他的介绍及其安装使用可以参考http://blog.chinaunix.net/u/11765/showart_239554.html;
有 两点可以注意下;其一:sh安装方式下linux默认安装目录一般为/usr/local/jprofilerX;其二 为${JPROFILER_HOME}/bin/linux-x86目录不一定要放在单独项LD_LIBRARY_PATH中,只要classpath中 能找到即可;
2、JProfiler、JProbe Profiler、Java Profiler三者是同一个产品么?
答案当然为否;三者都是业内非常优秀的Java性能监控工具,他们分别属于不同的公司;
JProfiler:http://www.ej-technologies.com
JProbe Profiler:http://www.quest.com;TOAD就是该公司的产品之一;
Java Profiler:http://www.yourkit.com