天天看點

運作時資料區-堆(Heap)- Minor GC、Major GC與Full GC

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

運作時資料區-堆(Heap)- Minor GC、Major GC與Full GC

運作結果:

[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