一份简单的GC日志分析(一)---新生代YoungGC

最近在看jvm相关的东西,因为要想能够自己jvm调优,首先要能够看得懂gc日志。不多bb,直接先上测试代码;

 public class Demo1 {
 ​
     public static void main(String[] args) {
         byte[] array1 = new byte[1024 * 1024];
         array1 = new byte[1024 * 1024];
         array1 = new byte[1024 * 1024];
         array1 = null;
         byte[] array2 = new byte[2 * 1024 * 1024];
     }
 }

这段代码网上一搜到处都是,我也是直接就拿过来用了。再贴上相关的jvm参数:

 -Xmn5M
 -Xms10M
 -Xmx10M
 -XX:SurvivorRatio=8
 -XX:PretenureSizeThreshold=10M
 -XX:+UseParNewGC
 -XX:+UseConcMarkSweepGC
 -XX:+PrintGCDetails
 -XX:+PrintGCTimeStamps
 -Xloggc:gc.log

先对这些参数做一个简单的概述:新老代使用ParNew+CMS的组合,新生代5M(Eden区4M,2个Survivor区都是0.5M),堆内存10M

那么执行一次的日志大致如下。因人而已哈,每次执行的结果都不一样,但是都差不多。(因为我使用的是IDEA测试的,所以新生代存放了一些额外的对象。如果是通过命令行启动的话,就是理想数据。在文章最后会给出)

 Java HotSpot(TM) 64-Bit Server VM (25.121-b13) for windows-amd64 JRE (1.8.0_121-b13), built on Dec 12 2016 18:21:36 by "java_re" with MS VC++ 10.0 (VS2010)
 Memory: 4k page, physical 25084628k(16630348k free), swap 26657492k(15385560k free)
 CommandLine flags: -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:MaxNewSize=5242880 -XX:NewSize=5242880 -XX:OldPLABSize=16 -XX:PretenureSizeThreshold=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC 
 0.142: [GC (Allocation Failure) 0.142: [ParNew: 4089K->512K(4608K), 0.0017101 secs] 4089K->1686K(9728K), 0.0019068 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 Heap
  par new generation   total 4608K, used 3745K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
   eden space 4096K,  78% used [0x00000000ff600000, 0x00000000ff928690, 0x00000000ffa00000)
   from space 512K, 100% used [0x00000000ffa80000, 0x00000000ffb00000, 0x00000000ffb00000)
   to   space 512K,   0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)
  concurrent mark-sweep generation total 5120K, used 1174K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
  Metaspace       used 3470K, capacity 4496K, committed 4864K, reserved 1056768K
   class space    used 383K, capacity 388K, committed 512K, reserved 1048576K

前面三行不用多说,从第4行开始逐行分析

  1. 0.142: [GC (Allocation Failure) 0.142: [ParNew: 4089K->512K(4608K), 0.0017101 secs] 4089K->1686K(9728K), 0.0019068 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

    1. 0.142:表明的是系统从启动到第一次回收,经过了0.142s,也就是执行142ms后第一次回收。

    2. [GC (Allocation Failure) :发生GC的原因是Allocation Failure(空间分配失败),因为代码在堆内存分配了三个1MB的数组之后。又尝试创建了一个2MB的数组,上面也曾提到过Eden区只有4MB。

    3. 0.142: [ParNew: 4089K->512K(4608K), 0.0017101 secs]:ParNew垃圾回收,此时年轻代有4089K的垃圾,回收之后只剩512K了。年轻代最大4608K。这个4608K,恰好就是4.5MB。也就是Eden区加上一个Survivor区的大小。耗时0.0017101s。但是此时Eden区我们只创建了3MB的对象。为什么占用了4089K的垃圾?这是因为虽然每个数组占用1MB,但是jvm里面这个对象还有对象头以及其他数据。所以占用的内存大于预期内存。

    4. 4089K->1686K(9728K), 0.0019068 secs]:这是说的java堆内存的情况。回收前4089K,和上面容量一致,说明此时老年代占用空间为0kb;9728K为老年代最大容量。恰好为9.5MB,也就是新生代可用空间(Eden区+1个Survivor区+老年代)。回收之后还剩1686K的对象在堆内存中。耗时0.0019068s。

    5. [Times: user=0.00 sys=0.00, real=0.00 secs] :这三个时间我没有过多去了解,大家自行百度哈。但是可以看出,时间为0.00,不代表没有,只是因为保留2位小数后是0.00,说明时间非常短。

  2. par new generation total 4608K, used 3745K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)

    eden space 4096K, 78% used [0x00000000ff600000, 0x00000000ff928690, 0x00000000ffa00000)

    from space 512K, 100% used [0x00000000ffa80000, 0x00000000ffb00000, 0x00000000ffb00000)

    to space 512K, 0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)

    说明parnew垃圾回收器负责的年轻代一共有4.5MB的可用内存。目前使用了3745K(差不多3.65M),其中包括了上一次垃圾回收剩余的512K,还包含新创建的2MB数组以及附带的空间占用。from space 的512K 100% used也就是存放的ParNew之后存放的垃圾。

  3. concurrent mark-sweep generation total 5120K, used 1174K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)

    CMS垃圾回收期一共管理5M内存,这次垃圾回收后存放了1174K的老年代对象。

  4. Metaspace used 3470K, capacity 4496K, committed 4864K, reserved 1056768K

    class space used 383K, capacity 388K, committed 512K, reserved 1048576K

    Metaspace 和class space用来存放一些类的信息和常量池等。

 

附录

  1. 命令行启动示例 
    java -Xmn5M -Xms10M -Xmx10M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10485760 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps com.demo.jvm.younggc.Demo1

     

  2. gc日志示例 
    0.094: [GC (Allocation Failure) 0.095: [ParNew: 4087K->512K(4608K), 0.0031348 secs] 4087K->666K(9728K), 0.0042052 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    Heap
     par new generation   total 4608K, used 2601K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
      eden space 4096K,  51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)
      from space 512K, 100% used [0x00000000ffa80000, 0x00000000ffb00000, 0x00000000ffb00000)
      to   space 512K,   0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)
     concurrent mark-sweep generation total 5120K, used 154K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
     Metaspace       used 2587K, capacity 4486K, committed 4864K, reserved 1056768K
      class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

     

欢饮大家纠错啊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章