Full GC (Ergonomics) 原因和实验

本文参考的圣思园张龙讲的JVM虚拟机

背景

首先程序如下:创建4个2M的对象

并设置如下参数:

-verbose:gc 会输出详细的垃圾回收信息
-Xms20M   初始值20m 堆空间
-Xmx20M   最大值20m
-Xmn10M     堆空间中,新生代的大小是10m
-XX:+PrintGCDetails  打印出垃圾回收的详细信息。
-XX:SurvivorRatio=8   eden:survivor 是8:1 但是survivor是两个。

因此栈内空间分布为:eden区8M,survivor 两个区分别是1M,老年代10M。

问题描述

我在程序实测的时候,出现了一下的状况,有的时候回出现Full GC,有的时候则不会。

令我较为奇怪的是,为什么会进行full gc。

补充:新生代回收为:对象在Eden中生成,当eden满的时候,还存活的对象会复制到一个survivor区,当此survivor满时,此区的存活对象将被复制到另一个survivor区,当第二个survivor也满的时候,从第一个survivor区复制过来的并且此时还存活的对象,将被复制到老年代。2个survivor是完全对称,轮流替换。而发生Full gc的为对整个jvm进行整理,包括yong,old。主要触发的时机,1)old满了,2)system.gc()。

解决测试

因为通过上面gc打印的日志,了解的内容无法分析出来其原理。因此我将程序在每次创建空间后打印

并添加了如下参数:

-XX:+PrintGC
-XX:+PrintHeapAtGC
-XX:+PrintGCTimeStamps

按照结果我分为未发生full gc,和发生full gc。

未发生full gc:

1
2
{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 6289K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 76% used [0x00000000ff600000,0x00000000ffc246b0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
 Metaspace       used 3444K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 375K, capacity 388K, committed 512K, reserved 1048576K
0.382: [GC (Allocation Failure) [PSYoungGen: 6289K->792K(9216K)] 6289K->4888K(19456K), 0.0067450 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 792K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 77% used [0x00000000ffe00000,0x00000000ffec6030,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000020,0x00000000ff600000)
 Metaspace       used 3444K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 375K, capacity 388K, committed 512K, reserved 1048576K
}
3
4
done
Heap
 PSYoungGen      total 9216K, used 5127K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 52% used [0x00000000ff600000,0x00000000ffa3beb8,0x00000000ffe00000)
  from space 1024K, 77% used [0x00000000ffe00000,0x00000000ffec6030,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000020,0x00000000ff600000)
 Metaspace       used 3451K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 376K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

上面的日志生意思如下:

过程新生代老年代gc清理量
edensurvivor1survivor2
生成3个变量6289000-
gc后0792040961401
加入第四个变量,程序结束后433579204096-

在加入三个变量后,eden空间为6289k,然后开始gc。(中括号内过程应该是这样,我也是个人猜测和推断,存疑)【先将eden中对象移存到survivor1,survivor1满了,再存survivor2,结果survivor2也满了。然后就将eden还存活的对象和其中一个survivor对象都移动到老年代。至于为什么加入第四个后eden到了将近4m,可能时程序结束的时候会有其他操作原因吧,这里不太清楚。】

发生full gc:

1
2
3
{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 8169K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 99% used [0x00000000ff600000,0x00000000ffdfa7c0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
 Metaspace       used 3167K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 344K, capacity 388K, committed 512K, reserved 1048576K
0.369: [GC (Allocation Failure) [PSYoungGen: 8169K->792K(9216K)] 8169K->6936K(19456K), 0.0686975 secs] [Times: user=0.09 sys=0.02, real=0.07 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 792K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 77% used [0x00000000ffe00000,0x00000000ffec6010,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6144K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 60% used [0x00000000fec00000,0x00000000ff200030,0x00000000ff600000)
 Metaspace       used 3167K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 344K, capacity 388K, committed 512K, reserved 1048576K
}
{Heap before GC invocations=2 (full 1):
 PSYoungGen      total 9216K, used 792K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 77% used [0x00000000ffe00000,0x00000000ffec6010,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6144K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 60% used [0x00000000fec00000,0x00000000ff200030,0x00000000ff600000)
 Metaspace       used 3167K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 344K, capacity 388K, committed 512K, reserved 1048576K
0.438: [Full GC (Ergonomics) [PSYoungGen: 792K->0K(9216K)] [ParOldGen: 6144K->6830K(10240K)] 6936K->6830K(19456K), [Metaspace: 3167K->3167K(1056768K)], 0.0130281 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap after GC invocations=2 (full 1):
 PSYoungGen      total 9216K, used 0K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6830K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 66% used [0x00000000fec00000,0x00000000ff2abbb8,0x00000000ff600000)
 Metaspace       used 3167K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 344K, capacity 388K, committed 512K, reserved 1048576K
}
4
done
Heap
 PSYoungGen      total 9216K, used 2372K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 28% used [0x00000000ff600000,0x00000000ff851320,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6830K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 66% used [0x00000000fec00000,0x00000000ff2abbb8,0x00000000ff600000)
 Metaspace       used 3198K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 350K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0
 

上面的日志生意思如下:

过程新生代老年代gc清理量
edensurvivor1survivor2
生成4个变量8169000-
gc后0792061441233
Full GC0006830106
程序结束2372006830-

在生成了4个2M的变量后,发生了gc,gc过程和上述一样。然后又发生了一次Full gc,而这里老年代并没有满。然后我看到了这个文章:https://blog.csdn.net/weixin_43194122/article/details/91526740。大致内容就是“如果晋升到老生代的平均大小大于老生代的剩余大小,则会返回true,认为需要一次full gc。”(中括号内过程应该是这样,我也是个人猜测和推断,存疑)【晋升到老年代数据为6M,这个平均大小的计算我看了看也没很弄懂,这里就进行了一次晋升,所以我们就按照6M。而老年代剩余的大小为4M所以发生了一次Full gc】。

验证

后来,我将老年代的空间减少为7M,那么这时,如果在第一种情况,第三个变量生成后发生gc,那么晋升到老年代的大小为4M,而剩余3M,所以按照道理也会发生full gc。而实验结果也是这样。

1
2
{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 6289K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 76% used [0x00000000ff600000,0x00000000ffc245d8,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 8192K, used 0K [0x00000000fee00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 8192K, 0% used [0x00000000fee00000,0x00000000fee00000,0x00000000ff600000)
 Metaspace       used 3360K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 368K, capacity 388K, committed 512K, reserved 1048576K
0.306: [GC (Allocation Failure) [PSYoungGen: 6289K->808K(9216K)] 6289K->4912K(17408K), 0.0062819 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 808K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 8192K, used 4104K [0x00000000fee00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 8192K, 50% used [0x00000000fee00000,0x00000000ff202020,0x00000000ff600000)
 Metaspace       used 3360K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 368K, capacity 388K, committed 512K, reserved 1048576K
}
{Heap before GC invocations=2 (full 1):
 PSYoungGen      total 9216K, used 808K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 8192K, used 4104K [0x00000000fee00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 8192K, 50% used [0x00000000fee00000,0x00000000ff202020,0x00000000ff600000)
 Metaspace       used 3360K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 368K, capacity 388K, committed 512K, reserved 1048576K
0.313: [Full GC (Ergonomics) [PSYoungGen: 808K->0K(9216K)] [ParOldGen: 4104K->4819K(8192K)] 4912K->4819K(17408K), [Metaspace: 3360K->3360K(1056768K)], 0.0102512 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap after GC invocations=2 (full 1):
 PSYoungGen      total 9216K, used 0K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 8192K, used 4819K [0x00000000fee00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 8192K, 58% used [0x00000000fee00000,0x00000000ff2b4d30,0x00000000ff600000)
 Metaspace       used 3360K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 368K, capacity 388K, committed 512K, reserved 1048576K
}
3
4
done
Heap
 PSYoungGen      total 9216K, used 4419K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 53% used [0x00000000ff600000,0x00000000ffa50f58,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 8192K, used 4819K [0x00000000fee00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 8192K, 58% used [0x00000000fee00000,0x00000000ff2b4d30,0x00000000ff600000)
 Metaspace       used 3438K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 374K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

然后,我又将老年代的空间变为14M,那么这时,如果在第二种情况,四个变量生成后发生gc,那么晋升到老年代的大小为6M,而剩余8M,所以按照道理不会发生full gc。而经过多次实验结果也没有见到full gc的发生。

1
2
3
{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 8169K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 99% used [0x00000000ff600000,0x00000000ffdfa7c0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 14336K, used 0K [0x00000000fe800000, 0x00000000ff600000, 0x00000000ff600000)
  object space 14336K, 0% used [0x00000000fe800000,0x00000000fe800000,0x00000000ff600000)
 Metaspace       used 3240K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 350K, capacity 388K, committed 512K, reserved 1048576K
0.338: [GC (Allocation Failure) [PSYoungGen: 8169K->808K(9216K)] 8169K->6960K(23552K), 0.0065596 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 808K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 14336K, used 6152K [0x00000000fe800000, 0x00000000ff600000, 0x00000000ff600000)
  object space 14336K, 42% used [0x00000000fe800000,0x00000000fee02030,0x00000000ff600000)
 Metaspace       used 3240K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 350K, capacity 388K, committed 512K, reserved 1048576K
}
4
done
Heap
 PSYoungGen      total 9216K, used 3180K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 28% used [0x00000000ff600000,0x00000000ff851320,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 14336K, used 6152K [0x00000000fe800000, 0x00000000ff600000, 0x00000000ff600000)
  object space 14336K, 42% used [0x00000000fe800000,0x00000000fee02030,0x00000000ff600000)
 Metaspace       used 3270K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 357K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值