一.G1 GC术语Overview

1.1 并发

  并发的意思是Java应用执行和垃圾收集活动可以同时进行

1.2 并行

  并行的意思是垃圾收集运算是多线程执行的,比如CMS垃圾收集器的年轻代就是并行的,并行与串行的区别如下图,左边为串行,右边为串行:

1.3 STW

  STW(stop the world)意思是在一个垃圾回收事件中,所有Java应用线程会被暂停。只有暂停,应用才不会产生新的垃圾,有益于垃圾收集器更好的标记垃圾对象。(这就像是你在家扫狗毛,肯定要把狗先关笼子,停止它的活动)

1.4 Region

  请先忘记这个图,学习G1过程中不会对每个代进行设置了

  G1垃圾收集器利用分而治之的思想将堆进行分区,划分为一个个的区域。每次收集的时候,只收集其中几个区域,以此来控制垃圾回收产生的STW

  G1和其他GC算法最大的区别是弱化分代概念,引入分区思想!!!

  如果要另外选择分区的尺寸,可以通过命令行选项:-XX:G1HeapRegionSize=n中进行设置

1.5 RSet

  G1垃圾收集器里每一个RSet对应的是一个Region内部对象引用情况,说白了就是存在Region中存活对象的指针。在标记存活对象的时候,G1使用RSet概念,将每个分区指向分区内的引用记录在该分区,避免对整个堆扫描,并行独立处理垃圾集合

  • 老年代对年轻代的引用,维护老年代分区指向年轻代分区的指针
  • 老年代对老年代的引用。在这里,老年代中不同分区的指针将被维护在老年代拥有分区的RSet中

  如下图,我们可以看到3各分区,x(年轻代分区)、y和z(老年代分区)。x有一个来自z的对内引用。这个引用记录在x的RSet中,分区z有2个对内引用,一个来自x一个来自y,因为年轻代分区作为一个整体回收的,所以只需记录来自y的对内引用,不用记录x的对内引用

1.6 CSet

  Collection Set,简称CSet。在垃圾收集过程中收集的Region集合可以称为收集集合(CSet),也就是在垃圾收集暂停过程中被回收的目标。GC时在CSet中的所有存活数据都会被转移,分区释放回空闲分区队列

  见下图,左边的年轻代收集CSet代表年轻代的一部分分区,右边的混合收集CSet代表年轻代的一部分区和老年代的多个分区:

  

1.7 PLAB

  Promotion Local Allocation Buffers,对象晋升到survivor分区或者老年代分区的过程是在GC线程的晋升本地分配缓冲区(PLAB)进行的,每个线程有独立的PLAB。作用是避免多线程竞争相同数据。和下面介绍的TLAB思想是一致的

1.8 TLAB

  Thread Local Allocation Buffers,线程本地分配缓存。JVM使用了TLAB这种线程专属的区间来避免多线程冲突(无锁方式),提高对象分配效率。TLAB本身占用了Eden空间,即JVM会为每一个线程都分配一块TLAB空间

1.9 IHOP

  InitiatingHeapOccupancyPercent,简称IHOP。缺省情况是Java堆内存的45%。当老年代的空间超过45%,G1会启动一次混合周期收集

  这也是G1和CMS之间较大的区别,G1的百分比是相对于整个Java堆而言的,CMS(CMSInitiatingOccupancyFraction)仅仅是针对老年代空间的占比。

  为什么G1如此设计???

  因为G1没有固定物理上分割一块内存作为老年代,而是用了Region的思想,这些Region可能是eden,survivor、老年代或者巨型分区,所以获取针对老年代本身的占用百分比没有意义

2.10 巨型分区

  巨型对象会以连续分区的形式来存放,这种就叫巨型分区。巨型对象无法利用年轻代里的TLAB和PLAB。在JDK 8u40之前,它只能在并发收集周期的清除阶段回收,但是在JDK 8u40之后,巨型分区可以在年轻代收集中和full GC被回收

二.G1的设计

2.1 为什么会有G1?

  为什么会有G1呢?因为并发、并行和CMS垃圾收集器都有2个共同的问题:

  1. 老年代收集器大部分操作都必须扫描整个老年代空间(标记,清除和压缩)。这就导致了GC随着Java堆空间而线性增加或减少
  2. 年轻代和老年代是独立的连续内存块,所以要先决定年轻代和年老代放在虚拟地址空间的位置

2.2 Region的设计

  上面说到,G1垃圾收集器利用分而治之的思想将堆进行分区,划分为一个个的区域。G1垃圾收集器将堆拆成一系列的分区,这样的话,大部分的垃圾收集操作就只在一个分区内执行,而不是整个堆或者整个代

2.3 设计目标

  G1的设计目标就是把必要的调整限定在以下2个:

  1. 设置最大的Java堆空间
  2. 设置指定GC暂停时间

  G1会通过调整Java堆尺寸大小来满足设定的暂停时间目标,暂停时间目标越短,年轻代空间越小,老年代空间相对越大

2.4 使用场景  

  G1 GC切分堆内存为多个区间(Region),从而避免很多GC操作在整个Java堆或者整个年轻代进行。G1 GC只关注你有没有存货对象,都会被回收并放入可用的Region队列。G1 GC是基于Region的GC,适用于大内存机器。即使内存很大,Region扫描,性能还是很高的

  如果现在采用的收集器没有问题,就不要选择G1,如果追求低停顿,那么G1已经是一个可尝试的选择,如果追求吞吐量,就不要选G1了

四.G1的垃圾回收

  G1的垃圾收集周期主要有4种类型:年轻代收集周期、多级并发标记周期、混合收集周期和full GC(转移失败的安全保护机制)

  这一节我会以应用启动的时间顺序来讲,这样比较易懂一点,也可以参照G1垃圾收集活动时序图:

4.1 年轻代收集

  应用刚启动,慢慢流量进来,开始生成对象。G1会选一个分区并指定他为eden分区,当这块分区用满了之后,G1会选一个新的分区作为eden分区,这个操作会一直进行下去直到达到eden分区上限,也就是说eden分区已经被占满,那么会触发一次年轻代收集

  年轻代收集首先做的就是迁移存活对象,它使用单eden,双survivor进行复制算法,它将存活的对象从eden分区转移到survivor分区,survivor分区内的某些对象达到了任期阈值之后,会晋升到老年代分区中。原有的年轻代分区会被整个回收掉

  同时,年轻代收集还负责维护对象年龄,存活对象经历过年轻代收集总次数等信息。G1将晋升对象的尺寸总和和它们的年龄信息维护到年龄表中,结合年龄表、survivor占比(--XX:TargetSurvivorRatio 缺省50%)、最大任期阈值(--XX:MaxTenuringThreshold 缺省为15)来计算出一个合适的任期阈值

  调优:我们可以通过--XX:MaxGCPauseMillis,调优年轻代收集,缩小暂停时间

4.2 并发标记周期

  随着时间推移,越来越多的对象晋升到老年代中,当老年代占比(相对于Java总堆而言)达到IHOP参数(上图的IHOP Trigger)之后,那么G1首先会触发并发标记周期(上图的Concurrent Marking Cycle),当完成后才会开始下一小节的混合垃圾收集周期  

  G1的并发标记循环分5个阶段:

  第一阶段:初始标记(上图Young Collection with Initial Mark),收集所有GC根(对象的起源指针,根引用),STW,在年轻代完成

  第二阶段:根区间扫描,标记所有幸存者区间的对象引用

  第三阶段:并发标记(上图Concurrent Marking),标记存活对象

  第四阶段:重新标记(上图Remark),是最后一个标记阶段,STW,很短,完成所有标记工作

  第五阶段:清除(上图Clean),回收没有存活对象的Region并加入可用Region队列

  调优:我们可以通过--XX:InitiatingHeapOccupancyPercent,配置适合应用的IHOP值(过大会可能转移失败,过小可能过早引起并发标记周期)

       我们也可以通过--XX:ConcGCThreads,增加并发线程数

4.3 混合收集周期

  当达到IHOP参数并完成上一小节的并发标记周期之后,混合收集周期就启动了,一个周期里的单次STW的混合收集和年轻代收集是类似的,唯一区别就是在混合收集过程中会包含一部分老年分区,所以也叫混合收集

  看上图的Mixed Collection Cycle,中间有好几段Mixed Collection,说明混合收集周期包含多次收集次数。那么什么影响收集次数呢?是固定的?还是?有两个参数比较重要:

  -XX:G1MixedGCCountTarget:缺省值为8,意思是能启动混合收集的数目设定一个物理限制。G1根据将回收的老年分区除以该参数值得到每次混合收集的老年代CSet最小数量

  -XX:G1HeapWastePercent:缺省值为5%,每次混合收集暂停,G1算出废物百分比,根据堆废物百分比,当收集达到参数时,不再启动新的混合收集

  调优:当暂停时间和运行时间呈现指数级增长,可以通过-XX:G1HeapWastePercent,调高该参数会有所帮助,但这也导致更多碎片化

4.4 full GC

  有2个条件同时满足则会触发full GC

  1.拷贝存活对象晋升(promotion)失败,无法找到可用的空闲分区,GC日志记录为to-space exhausted。或者分配巨型对象无法在老年代找到连续足够的分区

  2.当发生第一个条件后,G1会尝试增加堆使用量,如果扩展失败,那么会触发安全措施机制同时发生full GC

  full GC中,单个线程会对整个堆的所有代中所有分区做标记、清除以及压缩动作!!非常非常昂贵的操作!

搞懂G1垃圾收集器的更多相关文章

  1. 一篇文章搞懂G1收集器

    一.何为G1收集器 The Garbage-First (G1) garbage collector is a server-style garbage collector, targeted for ...

  2. 深入理解 Java G1 垃圾收集器--转

    原文地址:http://blog.jobbole.com/109170/?utm_source=hao.jobbole.com&utm_medium=relatedArticle 本文首先简单 ...

  3. G1 垃圾收集器

    概念先知 什么是垃圾回收 简单的说垃圾回收就是回收内存中不再使用的对象. 垃圾回收的基本步骤: 查找内存中不再使用的对象 释放这些对象占用的内存 查找内存中不再使用的对象 如何判断哪些对象不再被使用呢 ...

  4. G1垃圾收集器和CMS垃圾收集器 (http://mm.fancymore.com/reading/G1-CMS%E5%9E%83%E5%9C%BE%E7%AE%97%E6%B3%95.html#toc_8)

    参考来源 JVM 体系架构 堆/栈的内存分配 静态和非静态方法的内存分配 CMS 回收算法 应用场景 CMS 垃圾收集阶段划分(Collection Phases) CMS什么时候启动 CMS缺点 G ...

  5. 【JVM】7、深入理解Java G1垃圾收集器

    本文首先简单介绍了垃圾收集的常见方式,然后再分析了G1收集器的收集原理,相比其他垃圾收集器的优势,最后给出了一些调优实践. 一,什么是垃圾回收 首先,在了解G1之前,我们需要清楚的知道,垃圾回收是什么 ...

  6. G1 垃圾收集器入门

    最近在复习Java GC,因为G1比较新,JDK1.7才正式引入,比较艰难的找到一篇写的很棒的文章,粘过来mark下.总结这篇文章和其他的资料,G1可以基本稳定在0.5s到1s左右的延迟,但是并不能保 ...

  7. 转 G1垃圾收集器入门

    转自:http://blog.csdn.net/zhanggang807/article/details/45956325 最近在复习Java GC,因为G1比较新,JDK1.7才正式引入,比较艰难的 ...

  8. G1垃圾收集器的实现原理

    (G1垃圾收集器的实现原理.G1和CMS经常被单独拎出来问) https://tech.meituan.com/g1.html G1太复杂,说下CMS吧

  9. 详解 JVM Garbage First(G1) 垃圾收集器(转载)

    前言 Garbage First(G1)是垃圾收集领域的最新成果,同时也是HotSpot在JVM上力推的垃圾收集器,并赋予取代CMS的使命.如果使用Java 8/9,那么有很大可能希望对G1收集器进行 ...

随机推荐

  1. 使用 vant 的 v-lazy 实现图片 vue 在移动端的懒加载

    官方文档:https://youzan.github.io/vant/#/zh-CN/lazyload 引入 Lazyload 是 Vue 指令,使用前需要对指令进行注册 import Vue fro ...

  2. python数组冒号取值操作

    1.冒号的用法 1.1 一个冒号 a[i:j] 这里的i指起始位置,默认为0:j是终止位置,默认为len(a),在取出数组中的值时就会从数组下标i(包括)一直取到下标j(不包括j) 在一个冒号的情况下 ...

  3. loadrunner测试sql语句性能

    最初的想法是是想通过录制在SQL Server2008的操作来着的,无奈试了即便都录不到查询的sql语句,网上查资料全是关于SQL 2000的(这部分有经验的欢迎指教). 于是只能通过直接调用load ...

  4. pywinauto教程

    转:pywinauto教程https://blog.csdn.net/weixin_40161673/article/details/83246861 ** 一.环境安装**1.命令行安装方法pip ...

  5. 5G时代开启,这些新兴职业决定你的后半生

    近段时间,高考志愿填报成为牵动千万家庭的头等大事.事实上,除了学校间的差距外,专业的优劣也在很大程度上决定着人们未来职场生涯的潜力.血淋淋的事实告诉我们,只有选对专业,才能让自己的人生实现升华,并避免 ...

  6. case语句!

    1.case 语句概述(1)case 语句的作用使用 case 语句改写 if 多分支可以使脚本结构更加清晰.层次分明.针对变量的不同取值,执行不同的命令序列.2.case 语句的结构:case 变量 ...

  7. js判断ie和edge是否安装Adobe Reader PDF阅读器

    ie浏览器和edge浏览器,必须用Adobe Reader PDF阅读器才可以打开pdf文件,其他现代浏览器自带pdf阅读器,无需安装. 判断ie或者edge如果安装了,就浏览pdf文件:如果没安装就 ...

  8. office365激活码序列号密钥:

    亲测可用: NGCM9-FWB6X-9WKYC-GRWVD-63B3P  

  9. springboot+mybatis多数据源

    首先,既然是多数据源,那么我们就先看下数据源怎么配置的: javaconfig类似下面这样: MapperScan注解常用配置如下: basePackages:Base packages to sca ...

  10. leetcode菜鸡斗智斗勇系列(6)--- 检查一个string里面有几个对称的字段

    1.原题: https://leetcode.com/problems/split-a-string-in-balanced-strings/ Split a String in Balanced S ...