G1 GC_g1gc-程序员宅基地

技术标签: JVM  java  java进阶  

G1GC基本概念

  • G1 GC可以看做是CMS GC的重大升级改造
  • G1 GC的全称是Garbage-First,意为垃圾优先,哪一块的垃圾最多就优先清理他。
  • G1 GC最主要的设计目标是:将STW停顿的时间和分布,变成可预期且可配置的。(默认200ms)
    1. 垃圾回收过程中,一般垃圾的量在单位时间内都是固定的。
    2. 那么一下子把所有垃圾都处理完,就会导致了GC暂停的时间可能特别长。
    3. 如果每次处理一点,就会导致虽然暂停的时间比较短,但是整体垃圾回收的成本就会相对比较高。
    4. 为了平衡中间这个值,就产生了G1 GC的垃圾回收的算法。
    5. 设置了预期值之后,G1GC就会在自己执行了多次GC以后,调整自己GC策略:执行的频率、每次清理的垃圾数量等,慢慢地尽量控制在预期值以内。
    6. 这样的话就可以做到让GC暂停的时间跟整体的GC效率,比如吞吐量和延迟中间找到一个平衡点,这就是G1GC设计的一个出发点。
    7. 为了做到这件事情,G1GC打破了原先的串行并行CMS里堆内存整体的进行分区的年轻代(Eden、Servivor)、老年代(Old)的分代模式。
  • G1 GC 堆不在分成年轻代和老年代,而是划分为多个(默认是2048个)小块:Region。

每个小块,可能一会被定义成Eden区,一会被指定为Survivor区或者Old区。

这样内存上的管理:

  1. 颗粒度比较小
  2. 具体它用来做什么,都可以在运行期灵活地被G1GC所控制。
  • 启动参数:-XX:+UserG1GC   -XX:MaxGCPauseMillis=50

  • 这样划分以后,使得G1不必每次都区收集整个堆空间,而是以增量的方式来进行处理:每次只处理一部分内存块,称为此次GC的回收集(collection

set)。

  • 每次GC暂停都会收集所有年轻代的内存块,但一般只包含部分老年代的内存

块。

  • G1的另一个创新是,在并发阶段估算每个小堆块存活对象的总数。

依据这些垃圾的数量,就可以计算出那些小块现在垃圾比较多,就可以优先去处理垃圾比较多的。进而提高整个垃圾回收的效率。

  • 构建回收集的原则是:垃圾最多的小块会被优先收集。这也是G1名称的由

来。

G1 GC--配置参数

  • -XX:+UseG1GC:启用 G1 GC;
  • -XXG1NewSizePercent:初始年轻代占整个 Java Heap 的大小,默认值为 5%
    • 最开始只是用非常少量的这种小的块来作为整个Young区。
  • -XXG1MaxNewSizePercent:最大年轻代占整个 Java Heap 的大小,默认值为 60%
  • -XXG1HeapRegionSize:设置每个 Region 的大小,单位 MB,需要为 1、2、4、8、16、32 中的某个值,默认是堆内存的1/2000。如果这个值设置比较大,那么大对象就可以进入 Region 了;
  • -XXConcGCThreads:与 Java 应用一起执行的 GC 线程数量,默认是 Java 线程的 1/4,减少这个参数的数值可能会提升并行回收的效率,提高系统内部吞吐量。如果这个数值过低,参与回收垃圾的线程不足,也会导致并行回收机制耗时加长;
  • -XX+InitiatingHeapOccupancyPercent(简称 IHOP):G1 内部并行回收循环启动的阈值,默认为 Java Heap 45%高水位)。这个可以理解为老年代使用大于等于 45% 的时候,JVM 会启动垃圾回收。这个值非常重要,它决定了在什么时间启动老年代的并行回收;
    • 为何重要:因为如果老年代只使用了比较少的时候就做回收,这时要回收的整个对象比较少,垃圾也相对比较少,就会执行的特别快。如果这个比例特别大,整个老年代现在使用的量特别大,这时做垃圾回收时间就会特别长。
  • -XXG1HeapWastePercentG1停止回收的最小内存大小,默认是堆大小的 5%低水位)。GC 会收集所有的 Region 中的对象,但是如果下降到了 5%,就会停下来不再收集了。就是说,不必每次回收就把所有的垃圾都处理完,可以遗留少量的下次处理,这样也降低了单次消耗的时间;
  • -XX:G1MixedGCCountTarget:设置并行循环之后需要有多少个混合 GC 启动,默认值是 8 个。老年代 Regions的回收时间通常比年轻代的收集时间要长一些。所以如果混合收集器比较多,可以允许 G1 延长老年代的收集时间。
  • -XX:+G1PrintRegionLivenessInfo:这个参数需要和
  • -XX:+UnlockDiagnosticVMOptions 配合启动,打印 JVM 的调试信息,每个Region 里的对象存活信息。
  • -XX:G1ReservePercent:G1 为了保留一些空间用于年代之间的提升,默认值是堆空间的 10%。因为大量执行回收的地方在年轻代(存活时间较短),所以如果你的应用里面有比较大的堆内存空间、比较多的大对象存活,这里需要保留一些内存。
  • -XX:+G1SummarizeRSetStats:这也是一个 VM 的调试信息。如果启用,会在 VM 退出的时候打印出 Rsets 的详细总结信息。如果启用
  • -XX:G1SummaryRSetStatsPeriod 参数,就会阶段性地打印 Rsets 信息。
  • -XX:+G1TraceConcRefinement:这个也是一个 VM 的调试信息,如果启用,并行回收阶段的日志就会被详细打印出来。
  • -XX+GCTimeRatio:这个参数就是计算花在 Java 应用线程上和花在 GC 线程上的时间比率,默认是 9,跟新生代内存的分配比例一致。这个参数主要的目的是让用户可以控制花在应用上的时间,G1 的计算公式是 100/1+GCTimeRatio)。这样如果参数设置为9,则最多 10% 的时间会花在 GC 工作上面。Parallel GC 的默认值是 99,表示 1% 的时间被用在 GC 上面,这是因为 Parallel GC 贯穿整个 GC,而 G1 则根据 Region 来进行划分,不需要全局性扫描整个内存堆。
  • -XX:+UseStringDeduplication:手动开启 Java String 对象的去重工作,这个是 JDK8u20 版本之后新增的参数,主要用于相同String 避免重复申请内存,节约 Region 的使用。
  • -XXMaxGCPauseMills:预期 G1 每次执行 GC 操作的暂停时间,单位是毫秒,默认值是 200 毫秒,G1 会尽量保证控制在这个范围内。

G1GC的处理步骤 1

  1. 年轻代模式转移暂停(Evacuation Pause)

G1GC会通过前面一段时间的运行情况来不断的调整自己的回收策略和行为,以此来比较稳定地控制暂停时间,在应用程序刚启动时,G1还没有采集到什么足够的信息,这时候就处于初始的fully-young模式,当年轻代空间用满后,应用线程会被暂停,年轻代内存块中的存活对象被拷贝到存货区。如果还没有存活区,则任意选择一部分空闲的内存块作为存活区。

拷贝的过程成为转移(Evacuation),这和前面介绍的其他年轻代收集器是一样的工作原理。

  1. 并发标记(Concurrent Marking)

同时我们可以看到,G1GC的很多概念建立在CMS的基础上,所以下面的内容需要对CMS有一定的理解。

G1并发标记的过程与CMS基本上是一样的。G1的并发标记通过Snapshot-At-The-Beginning(起始快照)的方式,在标记阶段开始时记下所有的存活对象。即时在标记的同时又有一些变成了垃圾。通过对象的存活信息,可以构建出每个小堆块的存活状态,以便回收收集能高效地进行选择。

这些信息在接下来的阶段会用来执行老年代区域的垃圾收集。

有两种情况是可以完全并发执行的:

  1. 如果在标记阶段确定某个小堆块中没有存活对象,只包含垃圾;
  2. 在STW转移暂停期间,同时包含垃圾和存活对象的老年代小堆块。

当堆内存的总体使用比例达到一定数值,就会触发并发标记。这个默认比例是45%,但也可以通过JVM参数InitiatingHeapOccupancyPercent来设置。和CMS一样,G1的并发标记也是由多个阶段组成,其中一些阶段是完全并发的,还有一些阶段则会暂停应用线程。

G1GC的处理步骤 2

阶段1:Initial Mark(初始标记)

此阶段标记所有从GC根对象直接可达的对象。

阶段2:Root Region Scan(Root区扫描)

此阶段标记所有从”根区域“可达的存活对象。根区域包括:非空的区域,以及在标记过程中不得不收集的区域。

阶段3:Concurrent Mark(并发标记)

此阶段和CMS的并发标记阶段非常类似:只遍历对象图,并在一个特殊的位图中标记能访问到的对象。

阶段4:Remark(再次标记)

和CSM类似,这是一次STW停顿(因为不是并发的阶段),以完成标记过程。G1收集器会短暂地停止应用线程,停止并发更新信息的写入,处理其中的少量信息,并标记所有在并发标记开始时未被标记的存活对象。

阶段5:Cleanup(清理)

最后这个清理阶段为即将到来的转移阶段做准备,统计小堆块中所有存活的对象,并将小堆块进行排序,以提升GC的效率,维护并发标记的内部状态。所有不包括存活对象的小堆块在此阶段都被回收了。有一部分任务是并发的:例如空堆区的回收,还有大部分的存活率计算。此阶段也需要一个短暂的STW暂停。

G1GC的处理步骤 3

转移暂停:混合模式(Evacuation Pause(mixed))

并发标记完成之后,G1将完成一次混合收集(mixed collection),就是不只清理年轻代,还将一部分老年代区域也加入到回收集中。混合模式的转移暂停不一定紧跟并发标记阶段。有很多规则和历史数据会影响混合模式的启动时机。比如,假若在老年代中可以并发地腾出很多的小堆块,就没有了必要启动混合模式。

因此,在并发标记与混合转移暂停之间,很可能会存在多次young模式的转移暂停。

具体添加到回收集的老年代小堆块的大小及顺序,也是基于许多规则来判定的。其中包括指定的软实时性能指标,存活性,以及在并发标记期间收集的GC效率等数据,外加一些可配置的JVM选项。混合收集的过程,很大程度上和前面的fully-young gc是一样的。

G1GC的注意事项

特别需要注意的是,某些情况下G1触发了Full GC,这时G1会退化使用Serial收集器来完成垃圾的清理工作,它仅仅使用单线程来完成GC工作,GC暂停时间将达到秒级别的。会触发这种情况的条件如下:

  1. 并发模式失败

G1启动标记周期,但在Mix GC之前,老年代就被填满,这时候G1会放弃标记周期。

解决办法:增加堆大小,或者调整周期(例如增加线程数-XX:ConcGCThreads等)。

  1. 晋级失败

没有足够的内存供存活对象或晋级对象使用,由此触发了Full GC(to-space exhausted/to-space overflow)。

补充:当G1GC做垃圾回收的时候,有很多对象需要从新生代晋升到老年代,晋升的时候发现没有足够的内存供这次晋升使用,这时候也会触发Full GC,然后进行GC退化。

解决办法:

  1. 增加-XX:G1ReservePercent选项的值(并相应增加总的堆大小)增加预留内存量。

补充:G1GC内部为了更有效的做GC,其实默认是保留一部分的内存的,用来做对象的复制。

  1. 通过减少-XX:InitiatingHeapOccupancyPercent (默认45%)提前启动标记周期,进入垃圾回收。这样空余的内存相对就多了。
  2. 也可以通过增加-XX:ConcGCThreads选项的值来增加并行标记线程的数目。
  1. 巨型对象分配失败

当巨型对象找不到合适的空间进行分配时,就会启动Full GC,来释放空间。

解决办法:增加内存或者增大-XX:G1HeapRegionSize

各个GC对比

GC如何选择

选择正确的 GC 算法,唯一可行的方式就是去尝试,一般性的指导原则:

  1. 如果系统考虑吞吐优先,CPU 资源都用来最大程度处理业务,用 Parallel GC;
  2.  如果系统考虑低延迟有限,每次 GC 时间尽量短,用 CMS GC;
  3.  如果系统内存堆较大,同时希望整体来看平均 GC 时间可控,使用 G1 GC。

对于内存大小的考量:

  1. 一般 4G 以上,算是比较大,用 G1 的性价比较高。
  2. 一般超过 8G,比如 16G-64G 内存,非常推荐使用 G1 GC。

最后讨论一个很多开发者经常忽视的问题,也是面试大厂常问的问题:JDK8 的默认 GC 是什么?

JDK9,JDK10,JDK11…等等默认的 GC 是什么?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/YimBa/article/details/125237371

智能推荐

web开发需求,CSS的行内样式与内联样式_行内样式三目运算-程序员宅基地

文章浏览阅读483次。第一个阶段,开发环境和工具准备浏览器 (Google,FireFox,…)下载,安装前端开发工具vscode,下载、安装 node、npm、webpack、webpack-cli、cnpm,配置前端开发环境下载、配置PHP和MySQL第二个阶段,前端入门,网页制作1,HTML:常用标签(div标签,p标签,span标签,a标签,img标签)锚点列表标签(有序列表,无序列表,自定义列表)表单标签表格标签标签分类标签语义化注释字符实体2,CSS:CSS介绍全局_行内样式三目运算

MySQL修改my.cnf配置不生效的解决方法_mysql 修改配置文件不生效-程序员宅基地

文章浏览阅读6.2k次,点赞2次,收藏3次。1,参数没有写到 [mysqld] 下面而是写到 配置文件的末尾处了,我今天犯的错就是这个2,没有重启3,没有退出当前会话4,修改派配置文件错误5,参数写错了,打脸6,修改了错误的配置文件这里只说了修改 my.cnf,并没有说清楚其绝对路径是哪个文件。也就是说,有可能修改的不是正确路径下的my.cnf文件。在MySQL中,是允许存在多个 my.cnf 配置文件的,有的能对整个系统环境产生影响,例如:/etc/my.cnf。有的则只能影响个别用户,例如:~/.my.cnf。M._mysql 修改配置文件不生效

SpringBoot扩展篇:Spring注入 @Autowired & @Resource_spring boot resource按类型注入-程序员宅基地

文章浏览阅读938次,点赞22次,收藏24次。Autowired注入是由AutowiredAnnotationBeanPostProcessor完成的。@Resource注入是由CommonAnnotationBeanPostProcessor完成的。由于两种方式代码重复率太高,原理基本一致,下面我们主要以AutowiredAnnotationBeanPostProcessor源码分析为主。AutowiredAnnotationBeanPostProcessor负责属性、方法的注入。_spring boot resource按类型注入

Qt5.9.4中利用QOpenGLWidget类进行opengl绘图_qt opgl绘制图片-程序员宅基地

文章浏览阅读3w次,点赞15次,收藏110次。首先打开Qt Creator,然后点击菜单 ,文件->新建文件和项目,如图所示:左边选择Application,右边选择Qt Widgets Application,点击Choose...,项目名称为myOpenGLShow,接着下一步,一直默认,到Details,如下:点击取消选中创建界面(G)。然后下一步,知道完成,程序显示的为mainwindow.cpp文件:接着是利用QOpenGLW..._qt opgl绘制图片

用JAVA重0开始刷数据结构与算法04--二维数组及滚动数组-程序员宅基地

文章浏览阅读66次。二维数组及滚动数组118. 杨辉三角难度简单给定一个非负整数 *numRows,*生成「杨辉三角」的前 numRows 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。示例 1:输入: numRows = 5输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]示例 2:输入: numRows = 1输出: [[1]]提示:1 <= numRows <= 30class Solution { //purpos

TCP 之 SYN_SENT状态-程序员宅基地

文章浏览阅读5.1w次,点赞13次,收藏37次。SYN_SENT是TCP连接的发起方第一次发给接受放的时候设置成的状态。可以通过netstat -ano查看其中 在"state" 中可能会有 SYN_SENT如果在"state"中出现大量的"SYN_SENT ",那么你很有可能中了蠕虫病毒.这类病毒为了感染别的计算机,它就要扫描别的计算机,在扫描的过程中对每个要扫描的计算机都要发出了同步请求,这也是出现许多SYN_S..._syn_sent

随便推点

粒子和粒子系统-程序员宅基地

文章浏览阅读146次。1.粒子材质和粒子几何体 创建粒子系统的点,可以存放在Geometry几何体中。使用Geometry的vertices保存点、colors保存点的颜色。但我们必须使用粒子的专用材质对象PointCloudMaterial(原名叫做ParticleBasicMaterial)设置材质。包含的属性如下列表: 名称/描述 color/PointCloud对象中所有粒子的颜色..._具有粒子参考系的几何体仅支持粒子网格方法是什么意思

Weblogic远程代码执行(CVE-2020-14645)_weblogic中如何打代码-程序员宅基地

文章浏览阅读1.5k次。声明好好学习,天天向上漏洞描述Weblogic是美国Oracle公司出品的一个Application Server,确切的说是一个基于JavaEE架构的中间件,Weblogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。攻击者可利用该漏洞实现远程代码执行。该反序列化的gadget存在与coherence包中。编号CVE-2020-14645。反序列化的对象,通过t3发送给weblogic即可。所以,这个只是生成payload的工具。影响范围Ora_weblogic中如何打代码

BCB如何编写,调用动态链接库DLL _bcb可以隐式调用动态库吗-程序员宅基地

文章浏览阅读3.1k次。一 编写动态链接库DLL DLL简称动态链接库,是Windows中程序的重要组成部分。想象一下,一个程序需要多人共同完成开发,怎么个共同法?这时我们就要考虑把程序分为好几个模块,团队每一个成员开发一个模块。问题来了:如何将模块组合并成一个完整系统?还有,我们开发的软件需要不断升级,如何升级?难道每次非得把整个工程重新编译一次再发布给用户吗?解决这些问题的科学办法,就是开发动态链接库DLL。现在_bcb可以隐式调用动态库吗

【QT】Ubuntu 16如何使用qt creator加载或者创建ros工程_qt如何打开ros项目-程序员宅基地

文章浏览阅读2.8k次,点赞2次,收藏22次。背景:通过qt creator来编写,编译,运行ros程序包。ros程序包也可以带有界面。其工程是一个ros工程(不是.pro,而是cmakelist.txt),使用cmake编译方式。步骤:(1)安装QT(最新版本):见 https://blog.csdn.net/ipfpm/article/details/80698659(2)设置快捷方式:这一步将要修改Qt Creato..._qt如何打开ros项目

高并发 高负载 网站系统架构_priceline数据库架构-程序员宅基地

文章浏览阅读3k次。高并发 高负载 网站系统架构注:我看到这篇文章写的太好了,可以没法转到CSDN上我就COPY了,看到下面激烈的评论,我也一并COPY了。不过还是要谢谢哪位作者了。这样的文章很少。 转自:http://www.toplee.com/blog/71.html我在CERNET做过拨号接入平台的搭建,而后在Yahoo&3721从事过搜索引擎前端开发,_priceline数据库架构

异构计算 文章_异构计算系统的优点-程序员宅基地

文章浏览阅读5.3k次,点赞2次,收藏11次。从桌面到移动:异构计算翻天覆地的技术变革http://www.csdn.net/article/2014-07-10/2820610-heterogeneous-computing-in-mobile/1_异构计算系统的优点