OutOfMemoryError 分析过程

最近在研究JVM优化方面的知识,今天就顺便用JVM的查看工具测试了一下当发生OutOfMemoryError的时候如何通过工具来分析出错原因。

需要的工具Eclipse Memory Analyzer。

1.在eclipse的run argument中输入以下VM参数(关于Xms,Xmx,Xmn的具体含义参考http://unixboy.iteye.com/blog/174173)。设置了堆空间为20M,年轻代为10M。通过参数-XX:+HeapDumpOnOutOfMemoryError指定发生OutOfMemoryError的时候dump下内存(文件名为java_pid〈进程ID〉.hprof)。通过参数 -XX:+PrintGCDetails -Xloggc:gc.log设置程序输出gc的信息到gc.log文件。

OutOfMemoryError 分析过程

2.以下为java代码

package com.fnk.spring.manager;

import java.util.LinkedList;

class TestGC {
	public static void main(String[] args) {
		 LinkedList<String> l = new LinkedList<String>();
		 while(true){
			 l.add(new String("Testttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"));
		 }
	}
}

 3. 以下为gc.log文件。

先说一下日志输出的结构:(1.6和1.5略微有一些不同,只是1.6对于时间统计更加细致)

[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]

<collector>GC收集器的名称

<starting occupancy1> 新生代在GC前占用的内存

<ending occupancy1> 新生代在GC后占用的内存

<pause time1> 新生代局部收集时jvm暂停处理的时间

<starting occupancy3> JVM Heap 在GC前占用的内存

<ending occupancy3> JVM Heap 在GC后占用的内存

<pause time3> GC过程中jvm暂停处理的总时间

那么第一行数据可以发现发生min GC的时候年轻代从7680K到1272K回收了6408K,堆空间从7680K到7632K回收了48K,说明有6360K的数据被转移到了年老代。

那么第二行数据可以发现发生Full GC的时候年轻代从1272K到0K回收了1272K,年老代从6360K到7629K增多了1269K,堆空间从7632K到7629K回收了3K。

通过观察年老代不断的增多,一直到上限10240K。最后当年轻代的数量达到7679K的时候就发生了outofmemory的错误。

可以发生eden的space是7680K,from和to space的都是1280k。因为from和to的空间不能同时使用,因此可用的年轻代空间是8960K。默认的eden和surver的空间比例是6:1.

0.386: [GC [PSYoungGen: 7680K->1272K(8960K)] 7680K->7632K(19200K), 0.0439756 secs] [Times: user=0.06 sys=0.00, real=0.05 secs] 
0.430: [Full GC [PSYoungGen: 1272K->0K(8960K)] [PSOldGen: 6360K->7629K(10240K)] 7632K->7629K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0241013 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
0.460: [Full GC [PSYoungGen: 7680K->5068K(8960K)] [PSOldGen: 7629K->10240K(10240K)] 15309K->15308K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0492533 secs] [Times: user=0.05 sys=0.00, real=0.05 secs] 
0.512: [Full GC [PSYoungGen: 7680K->7680K(8960K)] [PSOldGen: 10240K->10240K(10240K)] 17920K->17920K(19200K) [PSPermGen: 2065K->2065K(12288K)], 0.0475882 secs] [Times: user=0.05 sys=0.00, real=0.05 secs] 
0.559: [Full GC [PSYoungGen: 7680K->7480K(8960K)] [PSOldGen: 10240K->10240K(10240K)] 17920K->17720K(19200K) [PSPermGen: 2065K->2059K(12288K)], 0.0626773 secs] [Times: user=0.06 sys=0.00, real=0.06 secs] 
0.622: [Full GC [PSYoungGen: 7680K->7680K(8960K)] [PSOldGen: 10240K->10240K(10240K)] 17920K->17920K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0479926 secs] [Times: user=0.05 sys=0.00, real=0.05 secs] 
0.671: [Full GC [PSYoungGen: 7680K->7679K(8960K)] [PSOldGen: 10240K->10240K(10240K)] 17920K->17919K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0484853 secs] [Times: user=0.05 sys=0.00, real=0.05 secs] 
0.719: [Full GC [PSYoungGen: 7679K->7679K(8960K)] [PSOldGen: 10240K->10240K(10240K)] 17919K->17919K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0477472 secs] [Times: user=0.05 sys=0.00, real=0.05 secs] 
0.767: [Full GC [PSYoungGen: 7679K->7679K(8960K)] [PSOldGen: 10240K->10240K(10240K)] 17919K->17919K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0489797 secs] [Times: user=0.06 sys=0.00, real=0.06 secs] 
1.892: [Full GC [PSYoungGen: 7679K->0K(8960K)] [PSOldGen: 10240K->137K(10240K)] 17919K->137K(19200K) [PSPermGen: 2059K->2059K(12288K)], 0.0100488 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
Heap
 PSYoungGen      total 8960K, used 209K [0x073e0000, 0x07de0000, 0x07de0000)
  eden space 7680K, 2% used [0x073e0000,0x07414518,0x07b60000)
  from space 1280K, 0% used [0x07b60000,0x07b60000,0x07ca0000)
  to   space 1280K, 0% used [0x07ca0000,0x07ca0000,0x07de0000)
 PSOldGen        total 10240K, used 137K [0x069e0000, 0x073e0000, 0x073e0000)
  object space 10240K, 1% used [0x069e0000,0x06a02490,0x073e0000)
 PSPermGen       total 12288K, used 2065K [0x029e0000, 0x035e0000, 0x069e0000)
  object space 12288K, 16% used [0x029e0000,0x02be4558,0x035e0000)

4. 通过memery analyzer可以分析出内存泄漏发生在linkedlist

OutOfMemoryError 分析过程

总结:Memery Analyzer是一个很好的分析工具,在程序运行的时候可以通过Jmap dump下内存,然后通过它来分析。

  一个问题是,垃圾回收动作何时执行?

  • 当年轻代内存满时,会引发一次普通GC,该GC仅回收年轻代。需要强调的时,年轻代满是指Eden代满,Survivor满不会引发GC
  • 当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代
  • 当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载

  另一个问题是,何时会抛出OutOfMemoryException,并不是内存被耗空的时候才抛出

  • JVM98%的时间都花费在内存回收
  • 每次回收的内存小于2%

你可能感兴趣的:(java,jvm,memory,analyzer)