Minor GC、Major GC 與 Full GC
JVM在GC時,并不是都對三個記憶體(新生代、老年代、方法區)區域一起進行垃圾回收的,大部分時候回收的都是指新生代
針對HotSpot VM的實作,它裡面按照回收區域又分為兩大類:部分收集(Partial GC)、整堆收集(Full GC)
- 部分收集:不是完整收集整個Java堆的垃圾收集。其中又分為:
- 新生代收集(Minor GC / Young GC):隻是新生代的垃圾收集
- 老年代收集(Major GC / Old GC):隻是老年代的垃圾收集
- 目前,隻有CMS GC會有單獨收集老年代的行為
- 注意,很多時候Major GC和Full GC混淆使用,具體需要分辨是老年代回收還是整堆回收
- 混合回收(Mixed GC):收集整個新生代和部分老年代的垃圾
- 目前隻有G1 GC會有這種行為
- 整堆收集(Full GC):收集整個Java堆和方法區的垃圾
年輕代GC(Minor GC)觸發機制
- 當年輕代空間不足的時候,就會觸發Minor GC,這裡的年輕代指的是Eden代滿,Survivor滿不會觸發GC。(每次Minor GC)會清理年輕代記憶體)
- 因為Java對象大多數都具備朝生夕死的特性,是以Minor GC非常頻繁,一般回收速度也非常快。着一定義既清晰又易于了解
- Minor GC會引發STW,暫停其他的使用者線程,等垃圾回收結束使用者線程才恢複運作
老年代GC(Major GC / Full GC)觸發機制
Major GC:
- 指發生在老年代的GC,對象在老年代被回收時,我們說“Major GC”或者“Full GC”發生了
- 出現了Major GC,經常會伴随至少一次Minor GC(但非絕對的,在Parallel Scavenge收集器的收集政策裡就有直接進行Major GC的政策選擇過程)
- 也就是在老年代空間不足時,會先嘗試觸發Minor GC。如果空間還不足則觸發Major GC
- Major GC的速度一般比Minor GC的速度慢10倍以上,STW的時間更長
- 如果Major GC 之後空間還不足,就報OOM
Full GC:(Full GC時開發或者調優中盡量要避免的,這樣暫停時間會短一些)
- 調用System.gc( )時,系統建議執行Full GC,但是不必然執行
- 老年代空間不足
- 方法去空間不足
- 通過Minor GC後進入老年代的大小大于老年代可用空間
- 有Eden區,Survivo區向Survivor1區複制時,對象的大小大于To區可用記憶體,則把對象轉存到老年代,且老年代的可用記憶體小于該對象大小
示例代碼
public class TestHeapOOM {
public static void main(String[] args) {
int i = 0;
try {
List<String> list = new ArrayList<>();
String a = "alilo.com.cn";
while (true) {
list.add(a);
a = a + a;
i++;
}
} catch (Error e) {
System.out.println("循環了:" + i + "次");
}
}
}
設定JVM運作參數:
-Xms10m -Xmx10m -XX:+PrintGCDetails
運作結果:
[GC (Allocation Failure) [PSYoungGen: 1973K->504K(2560K)] 1973K->938K(9728K), 0.0008736 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2377K->440K(2560K)] 2812K->1658K(9728K), 0.0005807 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1844K->504K(2560K)] 3063K->2626K(9728K), 0.0005644 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2353K->424K(2560K)] 8060K->7034K(9728K), 0.0009582 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 424K->0K(2560K)] [ParOldGen: 6610K->4267K(7168K)] 7034K->4267K(9728K), [Metaspace: 2924K->2924K(1056768K)], 0.0037112 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) --[PSYoungGen: 1800K->1800K(2560K)] 6068K->7860K(9728K), 0.0009274 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 1800K->0K(2560K)] [ParOldGen: 6059K->6060K(7168K)] 7860K->6060K(9728K), [Metaspace: 2934K->2934K(1056768K)], 0.0026529 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 6060K->6060K(9728K), 0.0001840 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 6060K->5971K(7168K)] 6060K->5971K(9728K), [Metaspace: 2934K->2934K(1056768K)], 0.0057219 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
循環了:17次
Heap
PSYoungGen total 2560K, used 133K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
eden space 2048K, 6% used [0x00000000ffd00000,0x00000000ffd214e0,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 7168K, used 5971K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
object space 7168K, 83% used [0x00000000ff600000,0x00000000ffbd4e70,0x00000000ffd00000)
Metaspace used 2962K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 336K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0