今天在玩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í)行后
- a4 申請分配時
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空間) -
- GC結(jié)束后 + a4申請完后的,堆信息-新生代。
def new generation total 9216K, used 4456K [0, 4, 9)
新生代共9216k,使用了4456K。(4456K是a4使用的)
- 新生代中的eden區(qū)、from區(qū)、to區(qū)的堆信息
- GC結(jié)束后 + a4申請完后的,堆信息-新生代。
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%
- 元空間信息
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?
初步整理
- 空間分配擔(dān)保?
空間使用多出來了1M,分析可能是因為【空間分配擔(dān)?!俊?墒沁@塊好像挺復(fù)雜的,等再詳細(xì)了解后,進(jìn)一步寫。
- 空間分配擔(dān)保?
- Java8?
原先還在想,因為《深入理解Java虛擬機(jī)》的環(huán)境是Java7 。是否因環(huán)境Java8 導(dǎo)致?但實際測試Java7 一樣有此問題。排除了Java8的環(huán)境因素。
- Java8?
- 不知名隱藏規(guī)則?
應(yīng)該是還有一些JVM的規(guī)則機(jī)制沒有搞明白。
- 不知名隱藏規(guī)則?
End...寫在最后
- 看書很好,但要動手,總能發(fā)現(xiàn)不一樣的東西。
- 問題多了,知識也就多了。
- 還需要進(jìn)一步深入理解...
《深入理解Java虛擬機(jī)》看一遍神書是不夠的!??!
- 還需要進(jìn)一步深入理解...
- 最后,等我找答案...

