一份簡單的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

     

歡飲大家糾錯啊

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