由于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. C#帮助类:Base64

    public class Base64 { #region Base64加密 ///<summary> ///Base64加密 ///</summary> ///<par ...

  2. 以太坊系列之十四: solidity特殊函数

    solidity中的特殊函数 括号里面有类型和名字的是参数,只有类型是返回值. block.blockhash(uint blockNumber) returns (bytes32): hash of ...

  3. css css预处理器

    CSS预处理器(css preprocessor) 1.less: 2.sass: 3.scss: 4.stylus 参考: http://hao.jser.com/archive/2507/ htt ...

  4. react.js学习之路五

    最近没时间写博客,但是我一直在学习react,我发现react是一个巨大的坑,而且永远填不完的坑 关于字符串的拼接: 在react中,字符串的拼接不允许出现双引号“” ,只能使用单引号' ',例如这样 ...

  5. 'javac' 不是内部或外部命令,也不是可运行的程序

    win10 系统下'javac' 不是内部或外部命令,也不是可运行的程序 1.在系统变量下面配置 JAVA_HOME:你自己的jdk的路径 CLASSPATH= .;%JAVA_HOME%libdt. ...

  6. 一步步yum安装LNMP,脱坑笔记!!!

    更改国内yum源: 1.备份yum源文件,位置在/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/ ...

  7. 怎样将结构完全一样的两个表的内容合并到一个表中,SQL语句

      标签: SQL合并数据 2013-08-21 10:41 489人阅读 评论(0) 收藏 举报  分类: Oracle数据库(14)  select * into 新表名 from (select ...

  8. flask总结03

    一:flask的请求勾子 01:钩子概念说明: 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如: 在请求开始时,建立数据库连接: 在请求开始时,根据需求进行权限校验: 在请求结束时 ...

  9. Day45--js基本小结

    JavaScript基本总结 一:基本背景 01:注:ES6就是指ECMAScript 6.(2015 ECMAScript6 添加类和模块) ECMAScript和JavaScript的关系 199 ...

  10. docker image rm ubuntu 失败

    [root@hadoop14 ~]# docker image rm ubuntu Failed to remove image (ubuntu:v2): Error response from da ...