奇怪的GC (Allocation Failure)日志

今天在玩JVM的GC日志時,遇到了一個奇怪的現(xiàn)象。目前的知識還沒找到原因,先記錄下。找到原因有再補(bǔ)充~。

環(huán)境是:JDK8

1. 先上構(gòu)造場景的代碼。

/**
 * @Auther: jx
 * @Date: 2018/7/28 16:37
 * @Description: GC測試2
 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
 */
public class TestGC2 {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) {
        test();
    }

    private static void test() {
        byte[] a1, a2, a3, a4;
        a1= new byte[2*_1MB];
        a2= new byte[2*_1MB];
        a3= new byte[2*_1MB];
        a4= new byte[4*_1MB];
    }
}

代碼比較簡單,創(chuàng)建4個數(shù)組對象空間。

2. JVM 配置

2.1配置內(nèi)容
VM配置信息
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
2.2 配置說明
配置 說明
-verbose:gc 顯示GC的情況
-Xms20M 設(shè)置堆初始大小20M
-Xmx20M 設(shè)置堆最大大小20M
-Xmn10M 設(shè)置堆中 new Generation 新生代的大小為10M
-XX:+PrintGCDetails 輸出GC的詳細(xì)日志
-XX:ServivorRatio=8 設(shè)置 New Generation新生代中的 Eden區(qū)與Servivor區(qū)比例是8:1
-XX:+UseSerialGC 設(shè)置GC回收器模式是串型垃圾回收器
2.3 配置結(jié)果

這里需要對配置后,進(jìn)行說明Java堆中各個區(qū)域的空間情況。如下:

  • Java堆,共有 20M
  • 新生代,有10M
    • Eden區(qū),8M
    • Servivor From ,1M
    • Servior To ,1M
  • 老年代,有10M

堆內(nèi)存模型如下:


內(nèi)存模型

3. 推導(dǎo)內(nèi)存分配

  • a1,a2, a3 分配時
    因為分配a1,a2,a3大小為2M,Eden區(qū)的大小夠a1,a2,a3申請。申請后的內(nèi)存情況如下:

    a1,a2,a3申請空間后的情況

    黃色代表已使用,空著代表未使用。

    • a4 申請分配時
      這里詳細(xì)步驟如下。
      • ① 因為a4需要申請4M空間,但現(xiàn)在Eden區(qū)只有2M Free的空間
      • ② From區(qū)還有1M空間,也無法滿足 a4的申請。
      • ③ 故此需要執(zhí)行一次MinorGC才能夠給 Allocation分配 a4的4M空間.
      • ④ MinorGC 開始執(zhí)行,首先會開始處理a1,a2,a3的空間。
      • ⑤ 因為a1,a2,a3有2M的空間,同時大于From區(qū) 1M的空間。
      • ⑥ 故此,會將a1,a2,a3移到Tenured老年代區(qū)域。
        執(zhí)行后的內(nèi)存空間模型如下:


        Minor GC執(zhí)行后

4. 推導(dǎo)GC日志

通過上面的內(nèi)存模型分析,推測GC日志可能如下:

[GC (Allocation Failure) [DefNew: 6144K->0K(9216K), 0.0040708 secs] 0K->0K(19456K), 0.0041138 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
 def new generation   total 9216K, used 4456K [0, 4, 9)
  eden space 8192K,  50% used [0, 4, 8)
  from space 1024K,   0% used [0, 1, 1)
  to   space 1024K,   0% used [0, 0, 0)
 tenured generation   total 10240K, used 6144K [0, 6, 10)
   the space 10240K,  60% used [0, 6, 6, 10)
 Metaspace       used 224K, capacity 2280K, committed 2368K, reserved 4480K

解釋說明:

  • 1.GC信息
    [GC (Allocation Failure) [DefNew: 6144K->0K(9216K), 0.0040708 secs] 0K->0K(19456K), 0.0041138 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    一次分配失敗GC,處理新生代從6144K到0 k空間(新生代共9216K空間),堆 共19456K空間)
    1. GC結(jié)束后 + a4申請完后的,堆信息-新生代。
      def new generation total 9216K, used 4456K [0, 4, 9)
      新生代共9216k,使用了4456K。(4456K是a4使用的)
      1. 新生代中的eden區(qū)、from區(qū)、to區(qū)的堆信息
eden space 8192K,  50% used [0, 4, 8)
# eden區(qū)空間共8192K,使用50%。
  from space 1024K,   0% used [0, 1, 1)
# from區(qū)空間共1024K,使用0%
  to   space 1024K,   0% used [0, 0, 0)
# to 區(qū)空間共1024K,使用0%
    1. 元空間信息
 Metaspace       used 224K, capacity 2280K, committed 2368K, reserved 4480K

5. 實際GC日志

實際情況卻讓我有點不明白,先看結(jié)果。

[GC (Allocation Failure) [DefNew: 7177K->1024K(9216K), 0.0040750 secs] 7177K->5207K(19456K), 0.0041222 secs] [Times: user=0.00 sys=0.01, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 7408K [0x05200000, 0x05c00000, 0x05c00000)
  eden space 8192K,  77% used [0x05200000, 0x0583c210, 0x05a00000)
  from space 1024K, 100% used [0x05b00000, 0x05c00000, 0x05c00000)
  to   space 1024K,   0% used [0x05a00000, 0x05a00000, 0x05b00000)
 tenured generation   total 10240K, used 4183K [0x05c00000, 0x06600000, 0x06600000)
   the space 10240K,  40% used [0x05c00000, 0x06015ec0, 0x06016000, 0x06600000)
 Metaspace       used 224K, capacity 2280K, committed 2368K, reserved 4480K
  • 首先,new generation 共9M,使用了7M.
    • eden,共8M,用了77%,大概是6M.
    • from,共1M,用了100%,是1M.
  • Tenuerd Generation 共10M,使用了4M.

看到這個結(jié)果,有點懵...有以下幾個疑惑:

  • 問題1. a1,a2,a3,a4總共申請的空間是2+2+2+4 =10M。
    而為什么使用 New Generation + Tenuerd Generation = 11M ?哪里多出來了1M?(見鬼了...)
  • 問題2. New Generation 為什么是使用了7M?
    其中,eden區(qū)為什么是6M?
    From區(qū)又為什么會被使用?而且是使用了全部的1M.
  • 問題3. Tenuerd Generation 為什么只有4M?
初步整理
    1. 空間分配擔(dān)保?
      空間使用多出來了1M,分析可能是因為【空間分配擔(dān)?!俊?墒沁@塊好像挺復(fù)雜的,等再詳細(xì)了解后,進(jìn)一步寫。
    1. Java8?
      原先還在想,因為《深入理解Java虛擬機(jī)》的環(huán)境是Java7 。是否因環(huán)境Java8 導(dǎo)致?但實際測試Java7 一樣有此問題。排除了Java8的環(huán)境因素。
    1. 不知名隱藏規(guī)則?
      應(yīng)該是還有一些JVM的規(guī)則機(jī)制沒有搞明白。

End...寫在最后

    1. 看書很好,但要動手,總能發(fā)現(xiàn)不一樣的東西。
    1. 問題多了,知識也就多了。
    1. 還需要進(jìn)一步深入理解...
      《深入理解Java虛擬機(jī)》看一遍神書是不夠的!??!
  • 最后,等我找答案...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容