由于Full GC的耗时是Minor GC的十倍左右,所以Full GC的频率设计得比Minor GC低得多。现总结一下触发Full GC的情况。

在那些实现了CMS的比较新的虚拟机中,如果配置了-XX:+UseConcMarkSwapGC,则启用CMS回收算法,CMS会周期性地检查老年代的情况,每隔一定时间(默认2秒),就检查是否需要对老年代进行一次CMS回收,判断的依据如下:

1、如果没有设置-XX:+UseCMSInitiatingOccupancyOnly,虚拟机会根据收集的数据决定是否触发(建议线上环境带上这个参数,不然会加大问题排查的难度)。
2、老年代使用率达到阈值 CMSInitiatingOccupancyFraction,默认92%。
3、永久代的使用率达到阈值 CMSInitiatingPermOccupancyFraction,默认92%,前提是开启 CMSClassUnloadingEnabled
4、新生代的晋升担保失败。
 

CMS分为两种模式,background和foreground,background采用concurrent remark模式,可以和用户进程并行,而foreground则必须要stop the world(STW)。周期性的CMS采用的是background的方式,而主动的GC则采用foreground方式。主动的GC肯定是Full GC,反之则未必,因为Full GC不是只在CMS中存在的,并且Full GC也可以是并行的Full GC(区别于正常的Full GC),采用并行的Full GC在Old GC阶段走的是background式的CMS,可参考寒泉子《jvm源码分析之SystemGC完全解读》一文。本文的重点也是Full GC。

因为Full GC所用的时间较长,为了充分发挥CMS的优势,通常都会配置-XX:+UseCMSInitiatingOccupancyOnly,让CMS周期性的以和用户现场并行的方式进行垃圾回收,这也是CMS设计的初衷。

但是呢,因为CMS采用标记-清理的方式进行GC,所以会产生碎片,时间久了,碎片就会很多,所以一般来说,进行了一段时间CMS之后,如果开启了UseCMSCompactAtFullCollection(默认为true开启),在foreground的时候就要采用一次压缩,这时采用Serial Old或Parallel Old这些采用标记-整理算法的GC方式(CMS采用的是标记-清理算法)进行回收。具体多少次full gc (foreground CMS)之后进行一次压缩,取决于-XX:CMSFullGCsBeforecompact(默认为0)。源码如下:

*should_compact = UseCMSCompactAtFullCollection && 
((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction)
|| GCCause::is_user_requested_gc(gch->gc_cause())
|| gch->incremental_collection_will_fail(true /* consult_young */)
);

从源码可以看出,除了达到一定次数之外,如果用户调用了System.gc()以及发生了promotion failed,也会进行一次压缩。同时也可以看出,foreground不一定会采用压缩,所以那些说foreground就是mark swap compact(msc)的是不对的。

但是周期性的CMS(background)只会回收老年代,除了周期性的进行GC之外,还有一些紧急情况,需要主动触发GC(foreground),主动触发的GC会连带一次Minor GC,所以也称为Full GC。主动触发的GC是会暂停所有用户现场的,俗称stop the world(STW)。

在那些没有实现CMS的老虚拟机或者没有开启CMS的虚拟机中,每一次Old GC都是Full GC,且会STW,当然因为除了CMS之外,其他的老年代回收算法都是采用标记-整理的方式,所以肯定也是压缩的,。

如果正在进行CMS回收,又触发了一次Full GC,则Full GC会抢占回收执行机会,停止CMS,采用Serial Old或Parallel Old这些采用标记-整理算法的GC方式(CMS采用的是标记-清理算法)进行Full GC。

下面是一些会触发Full GC的情况

1.System.gc()

在没有开启DisableExplicitGC的情况下,虽然只是建议,但是很多情况下,都会调用Full GC的,比如在原本应进行CMS的时候。System.gc()一般都是用在要释放堆外内存的时候使用。

2.老生代内存不足的时候

这种情况通常是对象要晋升到老年代中时,发现老年代的内存不足了,所以要引发一次Full GC。对象的晋升分为正常晋升和提前晋升。

3.永生区空间不足时

有些虚拟机把方法区也放到堆中管理,当加载的类太多时,永生区内存不足需要回收,也会触发Full GC

4.冒险失败之后

在Minor GC时发现to去的内存不足,则将Eden区和from区的内存全部晋升到老年区,清空新生代。但是如果此时老年区内存不足,则会冒险失败,冒险失败之后,对象仍然留在新生代(此时的Eden区和from区都接近99%),然后出发一次Full GC,这样便于下次如果还有冒险,可以增加冒险成功的几率。

5.HandlePromotionFailure设置为false或者历年平均晋升对象的大小大余老年代剩余连续空间

在Minor GC之前,虚拟机会检查老年代剩余连续空间是否大余新生代所有对象总大小,如果大余,则说明Minor GC绝对安全;如果小于,则会检查HandlePromotionFailure设置是否担保失败,如果不担保,则在Minor GC之前进行一次Full GC;如果担保,则再检查历年平均晋升对象的大小是否大余老年代剩余连续空间,如果大余,则不冒险,在Minor GC之前进行一次Full GC;如果小于,则冒险,进入情况4。

6.分配大对象时(和2其实是一样的,但是因为特殊,所以单独拿出来说)

如果直接要分配一个大对象,并且这个大对象的大小超过Eden区的一半,这个对象就会直接分配在老年代,此时如果老年代空间不足,出发一次Full GC,而不出发Minor GC。但是需要注意的是,如果分配的是TLAB而不是真正的大对象,那么不会导致full gc,而是调整TLAB的大小。

7.执行jmap -histo:live或者jmap -dump:live的时候

这属于强制让虚拟机执行一次full GC。

触发Full GC的时机的更多相关文章

  1. 触发Full GC执行的情况

    除直接调用System.gc外,触发Full GC执行的情况有如下四种. 1. 旧生代空间不足 旧生代空间只有在新生代对象转入及创建为大对象.大数组时才会出现不足的现象,当执行Full GC后空间仍然 ...

  2. GC之三--GC 触发Full GC执行的情况及应对策略

    1.System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数. ...

  3. 触发Full GC执行的情况 以及其它补充信息

    除直接调用System.gc外,触发Full GC执行的情况有如下四种.1. 旧生代空间不足旧生代空间只有在新生代对象转入及创建为大对象.大数组时才会出现不足的现象,当执行Full GC后空间仍然不足 ...

  4. GC的时机

    说到JVM,GC(垃圾回收)是非常重要的机制. 那么首先的问题是: GC在什么时候会发生? GC的触发包括两种情况:1.程序调用System.gc()的时候.2.系统自身决定是否需要GC. 系统进行G ...

  5. GC之八--GC 触发Full GC执行的情况及应对策略

    目录: GC之一--GC 的算法分析.垃圾收集器.内存分配策略介绍 GC之二--GC日志分析(jdk1.8)整理中 GC之三--GC 触发Full GC执行的情况及应对策略 gc之四--Minor G ...

  6. 由「Metaspace容量不足触发CMS GC」从而引发的思考

    https://mp.weixin.qq.com/s/1VP7l9iuId_ViP1Z_vCA-w 某天早上,毛老师在群里问「cat 上怎么看 gc」. 好好的一个群 看到有 GC 的问题,立马做出小 ...

  7. java触发full gc的几种情况概述

    前言 近期被问及这个问题,在此记录整理一下. System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full ...

  8. Minor GC 和 Full GC的时机

    一.对象何时能够进入老年代 GC年龄判定 每进行一次GC过程,存活的对象的GC年龄都会+1:当对象逃过15次GC,年龄达到15岁时,即可进入老年代 可以通过-XX:MaxTenuringThreshl ...

  9. 触发full gc的条件

    1.调用System.gc 2.老年代空间不足 3.永生区空间不足 4.CMS GC时出现promotion failed和concurrent mode failure 5.统计得到的Minor G ...

随机推荐

  1. Arduino I2C + DS1307实时时钟

    主要特性 DS1307是Maxim的串行.I2C实时时钟芯片.主要特性有: 工作电压:主电源电压4.5~5.5V,电池电压2.0~3.5V 功耗:电池供电.备份模式时<500nA 接口:I2C, ...

  2. wp面试题

    初级工程师 解释什么是依赖属性,它和以前的属性有什么不同?为什么在WPF会使用它? 什么是样式什么是模板 绑定(Binding )的基础用法 解释这几个类的作用及关系: Visual, UIEleme ...

  3. c#递归理解

    什么是递归函数? 任何一个方法既可以调用其他方法又可以调用自己,而当这个方法调用自己时,我们就叫它递归函数或者递归方法! 说白了,就是调用自己. 通常递归有两个特点:     1.递归方法一直会调用自 ...

  4. C# enum 枚举 反射

    枚举遍历 public enum EMyType { [System.ComponentModel.Description("A类型")] TypeA = 1, [System.C ...

  5. CentOS 系统管理与yum软件仓库搭建

    重启 reboot shutdown -r now init 6 关闭 init 0 shutdown -h now shutdown -h 20:25 #8点25关机查看内存 free CPU利用率 ...

  6. html5 video使用autoplay属性时,声音混乱

    html5 video使用autoplay属性时,声音混乱 页面代码 Index.html <html xmlns="http://www.w3.org/1999/xhtml" ...

  7. MooseFS分布式文件系统介绍

    一.简介 MooseFS是一个具备冗余容错功能的分布式网络文件系统,它将数据分别存放在多个物理服务器或单独磁盘或分区上,确保一份数据有多个备份副本.对于访问的客户端或者用户来说,整个分布式网络文件系统 ...

  8. iOS系统各个版本的占比查询

    目的:为了向大多数看齐,我们要实时了解应用系统的使用占比 1.苹果官网查询各个系统的占比: Apple 2.各种设备各种系统的占比 第三方

  9. [SCOI2009]windy数 BZOJ1026 数位dp

    题目描述 windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之间,包括A和B,总共有多少个windy数? 输入输出格式 输 ...

  10. 24.Letter Combinations of a Phone Number(电话号对应的字符组合)

    Level:   Medium 题目描述: Given a string containing digits from 2-9 inclusive, return all possible lette ...