今天tomcat的jvm崩了,一直jvm崩掉,每次也就看了一下内存区域,判断大概是内存问题,今天决定好好分析一下,整理了网上的一些资料。

1.crash文件
如果有一个严重的错误引起Java进程非正常退出,我们叫Crash,这时候会产生一个日志文件。生成在工作目录下,名字为 hs_err_pidxxxx.log,可以修改配置来改变
java -XX:ErrorFile=/var/log/java/java_error_%p.log

2.crash头部

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0xb7a0d926, pid=6028, tid=1876777888
#
# JRE version: 6.0_18-b07
# Java VM: Java HotSpot(TM) Server VM (16.0-b13 mixed mode linux-x86 )
# Problematic frame:
# V  [libjvm.so+0x5a2926]
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#




文件头中有很多有用的信息,“EXCEPTION_ACCESS_VIOLATION ”意味着Java应用Crash的时候,正在运行JVM自己的代码,而不是外部的Java代码或其他类库代码。这种情况很可能是JVM的Bug,但是也不一定。除了“EXCEPTION_ACCESS_VIOLATION ”,还有可能是别的信息,例如“SIGSEGV(0xb)”,意味着JVM正在执行本地或JNI的代码;EXCEPTION_STACK_OVERFLOW”意味着这是个栈溢出的错误。


另一个有用的就是


# Problematic frame:
# V  [libjvm.so+0x5a2926]




它说明Crash的时候,JVM正在从哪个库文件执行代码。除了“V”以外,还有可能是“C”、“j”、“v”、“J”。具体的表示意思如下:


FrameType Description: 

C: Native C frame 

j: Interpreted Java frame 

V: VMframe 

v: VMgenerated stub frame 

J: Other frame types, including compiled Java frames




3.线程部分


当jvm crash时在运行的线程,详细内容如下



---------------  T H R E A D  ---------------

Current thread (0x08064800):  GCTaskThread [stack: 0x6fd55000,0x6fdd6000] [id=6038]

siginfo:si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0x0000000c

Registers:
EAX=0x00000000, EBX=0x9f2807e8, ECX=0x00000008, EDX=0x9f280701
ESP=0x6fdd4e80, EBP=0x6fdd4ee8, ESI=0x6fdd4f38, EDI=0x00000003
EIP=0xb7a0d926, CR2=0x0000000c, EFLAGS=0x00010293

Top of Stack: (sp=0x6fdd4e80)
0x6fdd4e80:   c5d623b6 01064800 00000001 00000031
0x6fdd4e90:   c5d623b7 00000400 6fdd4ed8 b79a803e
0x6fdd4ea0:   c5d623b6 00000006 00dd4ee8 9f2807f0
0x6fdd4eb0:   00000000 010a5cf0 6fdd4ee8 b777cd6b
0x6fdd4ec0:   080b5e40 6fdd4f38 00000af7 00000af7
0x6fdd4ed0:   796f1c9e 08060210 00000001 7fd26e00
0x6fdd4ee0:   6fdd4f38 00000003 6fdd4f18 b7a0e19e
0x6fdd4ef0:   080d5fa8 9f2807e8 00000001 6fdd4f38 

Instructions: (pc=0xb7a0d926)
0xb7a0d916:   0f 84 3d 02 00 00 c6 45 c3 00 8b 43 04 8d 48 08
0xb7a0d926:   8b 51 04 89 d7 c1 ff 02 85 d2 89 7d bc 0f 8e df 

Stack: [0x6fd55000,0x6fdd6000],  sp=0x6fdd4e80,  free space=1ff6fdd4814k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x5a2926]
V  [libjvm.so+0x5a319e]
V  [libjvm.so+0x5a5270]
V  [libjvm.so+0x324cbb]
V  [libjvm.so+0x55de9e]
C  [libpthread.so.0+0x55cc]




这里指明了,当crash时,程序正在运行垃圾回收线程,所以有理由怀疑是垃圾回收出了问题,然后是一大堆的blocked的tomcat线程。此处略过



4.内存状态部分


Heap
 PSYoungGen      total 7040K, used 6912K [0x9eda0000, 0x9f690000, 0xb42f0000)
  eden space 5440K, 100% used [0x9eda0000,0x9f2f0000,0x9f2f0000)
  from space 1600K, 92% used [0x9f2f0000,0x9f460000,0x9f480000)
  to   space 1600K, 91% used [0x9f500000,0x9f66c000,0x9f690000)
 PSOldGen        total 193344K, used 190843K [0x742f0000, 0x7ffc0000, 0x9eda0000)
  object space 193344K, 98% used [0x742f0000,0x7fd4ee08,0x7ffc0000)
 PSPermGen       total 16640K, used 16403K [0x702f0000, 0x71330000, 0x742f0000)
  object space 16640K, 98% used [0x702f0000,0x712f4e48,0x71330000)




这里可以看到,crash的时候eden space 100%使用了,有理由怀疑jvm在young gc的时候挂掉了。找了一下问题,最后在官方网站找到这个问题了


[url]http://www.oracle.com/technetwork/java/javase/6u18-142093.html 

[/url] 

Card-Marking Optimization Issue 

A flaw in the implementation of a card-marking performance optimization in the JVM can cause heap corruption under some circumstances. This issue affects the CMS garbage collector prior to 6u18, and the CMS, G1 and Parallel Garbage Collectors in 6u18. The serial garbage collector is not affected. Applications most likely to be affected by this issue are those that allocate very large objects which would not normally fit in Eden, or those that make extensive use of JNI Critical Sections (JNI Get/Release*Critical). 


This issue will be fixed in the next Java SE 6 update. 


Meanwhile, as a workaround to the issue, users should disable this performance optimization by -XX:-ReduceInitialCardMarks.

这段话主要三个意思:一是指这个bug影响的GC类型为1.6u18前的CMS类GC以及1.6u18的CMS、G1和并行类GC,而串行GC不受影响;二是指哪些程序会受影响,主要是那些会分配大量的大对象而eden区过小或者对JNI使用比较敏感的程序;三是指明了处理方法


那么此处是否符合前面的两个条件呢?通过JVM参数,我们发现本例中的GC类型未指定,也就是使用的是默认参数,那么默认的GC类型是什么呢?在JDK5.0之前默认的GC是串行GC,但是之后尤其是到了JDK6.0之后就更加智能化了,会依据机器的性能来进行指定,怎么个指定法呢?有以下三条原则:



1、如果你是使用服务器类JVM的话,那么就会由并行GC来取代串行GC;


2、当程序运行后,会首先去检查硬件环境,如果确定其性能满足服务器类机器的标准的话,就会运行服务器类JVM


3、什么样的机器符合服务器类的标准呢?CPU至少要在2核以上,物理内存在2G以上。



通过以上三条,可以确认我们服务器符合服务器类机器的标准,因此会使用并行GC,而且版本是6U18在这个bug的影响范围内。而且我们没有为这个tomcat配置内存,使用默认配置,内存比较小。


后续的处理方法


一给配置了Xms和Xmx;


二是使用-XX:-ReduceInitialCardMarks来解决这个bug。


三 是用 -XX:PermSize= 加大存放JVM加载的类型信息的内存


现在已经加了,先运行起来再观察。