天天看点

gc实例与gc报告的阅读

gc报告的阅读

首先我们看一条gc报告

D:\杂项\java>java -verbose:gc -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails  -XX:+UseSerialGC -XX:SurvivorRatio=8 testAllocation
[GC[DefNew: 7492K->980K(9216K), 0.0034913 secs] 7492K->7124K(19456K), 0.0037735 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]


Heap
 def new generation   total 9216K, used 3358K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
  eden space 8192K,  29% used [0x00000000f9a00000, 0x00000000f9c52728, 0x00000000fa200000)
  from space 1024K,  95% used [0x00000000fa300000, 0x00000000fa3f5100, 0x00000000fa400000)
  to   space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000)
 tenured generation   total 10240K, used 6144K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
   the space 10240K,  60% used [0x00000000fa400000, 0x00000000faa00030, 0x00000000faa00200, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2471K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
   the space 21248K,  11% used [0x00000000fae00000, 0x00000000fb069d58, 0x00000000fb069e00, 0x00000000fc2c0000)
No shared spaces configured.      

先看java运行的几个参数

-Xms20m -Xmx20m -Xmn10m说明堆的大小固定不变,为20m,其中年轻代为10m

-XX:+PrintGCDetails 让虚拟机打印出gc日志,最后输出当前内存各个区域的使用情况。注意,这是两部分内容,一个是gc日志,一个是内存使用情况。

-XX:+UseSerialGC 使用-XX:+UseSerialGC可以使用Serial+Serial Old模式运行进行内存回收(这也是虚拟机在Client模式下运行的默认值)

-XX:SurvivorRatio=8 说明eden区与一个Survivor区的大小比例为8。

至于[GC[DefNew: 7492K->980K(9216K), 0.0034913 secs] 7492K->7124K(19456K), 0.0037735 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]具体是什么意思

大家参阅

Java GC 日志详解

我就补充一点:

日志开头的[GC和[Full GC说明了此次垃圾收集的停顿类型,而不是用来区分新生代GC还是老年代GC。

我们看几个实例

D:\杂项\java>type testAllocation2.java
/**
 *
 *  -verbose:gc  -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails  -XX:SurvivorRatio=8
 *
 */
public class testAllocation2{
        private static int _1m=1024*1024;
        public static void main(String[] args) {
                byte[] all1,all2,all3,all4,all5;

                all1=new byte[_1m * 2];
                all2=new byte[_1m * 2];
                all3=new byte[_1m * 2];
                all4=new byte[_1m * 4];
        }
}


D:\杂项\java>javac testAllocation2.java


D:\杂项\java>java -verbose:gc  -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails  -XX:SurvivorRatio=8 testAllocation2
Heap
 PSYoungGen      total 9216K, used 7143K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 87% used [0x00000000ff600000,0x00000000ffcf9ff8,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000010,0x00000000ff600000)
 PSPermGen       total 21504K, used 2468K [0x00000000f9a00000, 0x00000000faf00000, 0x00000000fec00000)
  object space 21504K, 11% used [0x00000000f9a00000,0x00000000f9c691d0,0x00000000faf00000)


D:\杂项\java>      

上面的代码是我从<<深入理解java虚拟机>>第二章中引过来的。但是并没有发生gc呀?

花了好长时间,才知道得加上一个参数。

-XX:+UseSerialGC

不是说默认就是这个参数么?

我的java版本:

D:\杂项\java>java -version
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)      

搞不清楚了。

我们加上这个参数

D:\杂项\java>java -verbose:gc  -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:+UseSerialGC  -XX:SurvivorRatio=8 testAllocation2
[GC[DefNew: 6980K->468K(9216K), 0.0034679 secs] 6980K->6612K(19456K), 0.0037547 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]


Heap
 def new generation   total 9216K, used 4894K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
  eden space 8192K,  54% used [0x00000000f9a00000, 0x00000000f9e527b0, 0x00000000fa200000)
  from space 1024K,  45% used [0x00000000fa300000, 0x00000000fa3750f0, 0x00000000fa400000)
  to   space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000)
 tenured generation   total 10240K, used 6144K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
   the space 10240K,  60% used [0x00000000fa400000, 0x00000000faa00030, 0x00000000faa00200, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2471K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
   the space 21248K,  11% used [0x00000000fae00000, 0x00000000fb069cf8, 0x00000000fb069e00, 0x00000000fc2c0000)
No shared spaces configured.


D:\杂项\java>      

OK,发生gc了。

all1,all2,all3加入后,eden区域已经被占了6m了,本来就只有8m,all4的4m一来,马上就发生Minor gc

6m的对象中没有任何一个能放入一个survivor区,那没办法了,6m的对象直接进入老年代。

tenured generation   total 10240K, used 6144K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)

   the space 10240K,  60% used [0x00000000fa400000, 0x00000000faa00030, 0x00000000faa00200, 0x00000000fae00000)

能说明这个问题。

那么all4呢,它的4m,就还是放到eden区。

我们再看一个例子。

private static int _0_5M=1024*512;


  public static void main(String[] args) {
    byte[] all1,all2,all3,all4,all5;
    all1=new byte[1*_0_5M];
    all2=new byte[4*_0_5M];
    all3=new byte[4*_0_5M];
    all4=new byte[4*_0_5M];
    all5=new byte[4*_0_5M];


  }      

结果

D:\杂项\java>java -verbose:gc  -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:+UseSerialGC  -XX:SurvivorRatio=8 testAllocation
[GC[DefNew: 7492K->980K(9216K), 0.0036395 secs] 7492K->7124K(19456K), 0.0038973 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]


Heap
 def new generation   total 9216K, used 3358K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
  eden space 8192K,  29% used [0x00000000f9a00000, 0x00000000f9c52728, 0x00000000fa200000)
  from space 1024K,  95% used [0x00000000fa300000, 0x00000000fa3f5100, 0x00000000fa400000)
  to   space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000)
 tenured generation   total 10240K, used 6144K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
   the space 10240K,  60% used [0x00000000fa400000, 0x00000000faa00030, 0x00000000faa00200, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2471K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
   the space 21248K,  11% used [0x00000000fae00000, 0x00000000fb069d00, 0x00000000fb069e00, 0x00000000fc2c0000)
No shared spaces configured.


D:\杂项\java>      

all5产生时发生了minor gc,与上面的例子不同的时,最后:all2,all3,all4进入了老年代,而all1与all5共2.5m进入了eden区。

那怎么survivor还占用了95%,这个我估计是堆里的其他数据。大家忽略之。