遭遇OutOfMemoryError

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

系统运行环境:
硬件: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

你可能感兴趣的:(遭遇OutOfMemoryError)