天天看点

运行时数据区-堆(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