一次服务器上g1回收器发生fullgc的粗浅理解与记录

1.现场监控截图

监控到一次fullgc在这里插入图片描述
在这里插入图片描述

由上面两张图可以看出,

1. old区内存使用并不多,为何会fullgc。

2.年轻代确实没有进行gc,所以可以确定当时确实进行了fullgc。

2.gc log

我们服务器使用的是g1回收器,找到当时时间节点的gc log,截图如下:
在这里插入图片描述

3.分析log,提出问题

我们从监控中可以看到,fullgc时:

总计堆内存2051m -> 142m, 总共回收了 1927m

在年轻代,eden回收了 1532m, survivor44m,总计 1576m

说明老年代总共只回收了 1927 - 1576 = 351m

这个和监控中是能对应上的。 关键问题是,为什么old区使用很小,会进行fullgc?而且这个fullgc回收old区很少,Eden区回收很多?

4.什么时候会gc?

这个问题可以直接参考 https://blog.csdn.net/jiguansheng/article/details/105406343

我们知道会有内存担保,当Eden区尝试分配对象空间不足时会放在old区,old区也无法容纳才会fullgc

但是,上面说的情况对于g1情况是不适用的。我们来看看g1的full gc逻辑

以下解释来自网络
在这里插入图片描述

转移失败(Evacuation Failure)是指当G1无法在堆空间中申请新的分区时,G1便会触发担保机制,执行一次STW式的、单线程的Full GC。Full GC会对整堆做标记清除和压缩,最后将只包含纯粹的存活对象

G1在以下场景中会触发Full GC,同时会在日志中记录to-space-exhausted以及Evacuation Failure:

从年轻代分区拷贝存活对象时,无法找到可用的空闲分区

从老年代分区转移存活对象时,无法找到可用的空闲分区

分配巨型对象时在老年代无法找到足够的连续分区

G1启动标记周期,但在Mix GC之前,老年代就被填满,这时候G1会放弃标记周期。这种情形下,需要增加堆大小,或者调整周期(例如增加线程数-XX:ConcGCThreads等)。

由于G1的应用场合往往堆内存都比较大,所以Full GC的收集代价非常昂贵,应该避免Full GC的发生。

4.3.4  异常情况

并发标记周期开始后的FULL GC

启动了标记周期,但是在并发标记完成之前,就发生了Full GC,日志常常如下所示:

GC concurrent-mark-start开始之后就发生了FULL GC,这说明老年代空间不够用了,可能原因:老年代分区的回收速度比较慢,对象过快得从新生代晋升到老年代,有很多大对象直接在老年代分配。针对上述原因,可能需要做的调整有:调大整个堆的大小、更快得触发并发回收周期、让更多的回收线程参与到垃圾收集的动作中。

混合收集模式中的FULL GC

在一次混合收集之后跟着一条FULL GC,这意味着混合收集的速度太慢,在老年代释放出足够多的分区之前,应用程序就来请求比当前剩余可分配空间大的内存。针对这种情况我们可以做的调整:增加每次混合收集收集掉的老年代分区个数;增加并发标记的线程数;提高混合收集发生的频率。

疏散失败(转移失败)

在新生代垃圾收集快结束时,找不到可用的分区接收存活下来的对象,发送full gc。

增加整个堆的大小——通过增加 -XX:G1ReservePercent选项的值(并相应增加总的堆大小)。

通过减少 -XX:InitiatingHeapOccupancyPercent 提前启动标记周期。

巨型对象分配失败

如果在GC日志中看到莫名其妙的FULL GC日志,又对应不到上述讲过的几种情况,那么就可以怀疑是巨型对象分配导致的,这里我们可以考虑使用 jmap命令进行堆dump,然后通过MAT对堆转储文件进行分析。

以上参考https://km.sankuai.com/page/208897718

而且g1的fullgc也不是自己实现的,是调用的其他回收器,多为 serial

5.结论

根据上面的fullgc可能的情况:

G1在以下场景中会触发Full GC,同时会在日志中记录to-space-exhausted以及Evacuation Failure:

从年轻代分区拷贝存活对象时,无法找到可用的空闲分区

从老年代分区转移存活对象时,无法找到可用的空闲分区

分配巨型对象时在老年代无法找到足够的连续分区

G1启动标记周期,但在Mix GC之前,老年代就被填满,这时候G1会放弃标记周期。这种情形下,需要增加堆大小,或者调整周期(例如增加线程数-XX:ConcGCThreads等)。

由于G1的应用场合往往堆内存都比较大,所以Full GC的收集代价非常昂贵,应该避免Full GC的发生。

结合10:27分的请求情况,可以认为返回结果是 一个31行61列的map

在本地模拟其占有内存:约为10m。模拟代码

@Test
    public void testCsv() throws InterruptedException {
        // 31 61
        Thread.sleep(20000);
        String field = "fieldfieldfieldfieldfieldfield";
        String value = "valuevaluevaluevaluevaluevalue";
        List rows = Lists.newArrayList();
        for (int i = 0; i < 32; i++){
            Map row = Maps.newHashMap();
            for (int j = 0; j < 62; j ++){
                row.put(value + j, field);
            }
            rows.add(row);
        }
        System.out.println(rows);
        Thread.sleep(20000);
        List rows2 = Lists.newArrayList();
        for (int i = 0; i < 32; i++){
            Map row = Maps.newHashMap();
            for (int j = 0; j < 62; j ++){
                row.put(value + j, field);
            }
            rows2.add(row);
        }
        Thread.sleep(20000);
    }

使用内存情况用jconsole查看的情况
在这里插入图片描述
可以知道这样的请求结果约占10m。

我们在gclog中看到 g1的每个region是4m,此时我们的对象符合巨型对象(> region 50%)

理论上应该是此时巨型对象过多无法分配导致的

6.反思

排查链条过长

对于fullgc发生的情况一刀切,忽略了各回收器之间的差异

由于本人水平有限,难免有误,欢迎指正交流。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
G1垃圾回收也会存在Full GC的情况,尽管Full GC的发生代价很高,应该尽量避免。Full GC的出现可能意味着程序的运行出现了问题,需要仔细考虑为什么会触发Full GC。 Full GC是指对整个Java堆进行垃圾回收,包括Young Generation和Old Generation。在G1中,Full GC通常是由于一些特殊的情况触发的,例如内存压力过大、空间不足或者是Humongous对象分配等。 在Full GC过程中,整个堆内存都会被扫描和清理,这个过程是非常耗时的。因此,我们应该关注并且优化程序中可能导致Full GC发生的原因,以减少Full GC的频率和影响。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [一次服务器g1回收发生fullgc粗浅理解记录](https://blog.csdn.net/lhy18235303007/article/details/115774839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [G1垃圾回收详解](https://blog.csdn.net/w1014074794/article/details/128604545)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值