这里只要第一行即可,这一行指明了,当crash时,程序正在运行垃圾回收线程,所以有理由怀疑是垃圾回收出了问题,然后这个文件就指引我们来到了第三部分,dump出来的线程信息。
在略过上面N行的处于bolcked状态下的线程信息后,我们终于看到了此时的堆信息。由标红处我们发现,crash正处于eden区达到了100%要进行young gc的时候,因此我们有理由相信是由于young gc出了问题所致。但是什么问题呢?于是上google搜了一下“jvm crash young gc”。good luck!第一篇就找到了相应的解决方法,原来是这是jdk1.6u18的一个bug,官方文档介绍如下:
这段话主要三个意思:一是指这个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,在这个bug的影响范围内。而对于第二点,JVM参数只指定了512M内存,除去永久区的64M,而新生代与老生代的默认分配比例是1:8,因此新生代大约是在50M左右,的确不是一个很大的数字。当初也许是由于担心任务和web跑在一台机器上吧,因此将JVM的堆参数设得这么小。
后续的处理方法一是将任务的JVM参数标准化;二是使用-XX:-ReduceInitialCardMarks来解决这个bug!