JVM垃圾回收——G1垃圾收集器

这篇具有很好参考价值的文章主要介绍了JVM垃圾回收——G1垃圾收集器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、什么是G1垃圾收集器

二、G1垃圾收集器的内存划分

三、G1垃圾收集器的收集过程

 四、G1收集器的优缺点

五、G1收集器的JVM参数配置


一、什么是G1垃圾收集器

        Garbage First(简称G1)收集器是垃圾收集器技术发展史上里程碑式的成果,它摒弃了传统垃圾收集器的严格的内存划分,而是采用局部回收的设计思路和基于Region的内存布局形式。

        G1是一款主要面向服务端应用的垃圾收集器,在jdk6 update14时,就有了实验版本。而到了jdk7 update4之后移除了“Experimental”标识。它的目的是为了适应现在不断扩大的内存和不断增加的处理器数量,进一步降低暂停时间(pause time),同时兼顾良好的吞吐量。如今已经完全替代CMS垃圾收集器,CMS收集器在JDK9 中被废弃,在JDK 14中被移除。

二、G1垃圾收集器的内存划分

g1垃圾回收,JVM,jvm,java,G1

         从上面图上可以看到,G1垃圾收集器也是基于分代收集理论设计的,但是它的堆内存的布局与其他垃圾收集器的布局有很明显的区别,G1收集器不再按照固定大小以及固定数量的分代区域划分,而是把JAVA堆划分为2048个大小相等的独立的Region,每个Region大小可以通过参数-XX:G1HeapRegionSize设定,取值范围为1-32MB,且必须为2的N次幂。每一个Region都可以根据需要充当新生代的Eden区、S0和S1区或者老年代。在一般的垃圾收集中对于堆中的大对象,默认直接会被分配到老年代,但是如果它是一个短期存在的大对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放大对象。如果一个H区装不下一个大对象,那么G1会寻找连续的H区来存储。为了能找到连续的H区,有时候不得不启动Full GC。 G1的大多数行为都把H区作为老年代的一部分来看待。当一个对象的大小超过了一个Region容量的一半,即被认为是大对象。

        虽然G1仍然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,而是一系列区域(不需要连续,逻辑连续即可)的动态集合。由于G1这种基于Region回收的方式,可以预测停顿时间。G1会根据每个Region里面垃圾“价值”的大小,在后台维护一个优先级列表,每次根据用户设定的允许收集停顿的时间(-XX:MaxGCPauseMillis,默认为200毫秒)优先处理价值收益最大的Region。

三、G1垃圾收集器的收集过程

在了解G1收集过程之前,我们首先考虑几个问题

1、将java堆分成多个独立的Region后,Region里面存在的跨Region引用的对象是如何解决的?

答:G1收集器和其他垃圾收集器模型一样,存在跨代引用的解决方法是使用记忆集(Remembered Set)具体细节可以参考本人的另一篇博文中的跨代引用JVM垃圾回收——垃圾回收的一些细节实现_熟透的蜗牛的博客-CSDN博客

使用记忆集避免了全堆作为GC Roots扫描,但实际上G1收集器为每一个Region都维护了自己的记忆集,这些记忆集会记录下其他的Region指向自己的指针,并标记这些指针分别在那些卡页范围之内。G1的记忆集在存储结构的本质上是一种哈希表,key是其他Region的起始地址,value是卡表索引号的集合。这种双向卡表的结构比原来的卡表实现更复杂,也正是因为这种双向卡表和多Region的之间的引用导致G1收集器比其他收集器占用的内存要多。根据经验G1至少占用JAVA堆容量的10%-20%额外内存来维护收集器的工作。

2、G1是一个并发标记的收集器,那么在并发回收阶段,G1如果解决“漏标”的情况?如何解决在回收过程中重新分配到该Region上的新对象不被回收的?

答:G1是如何解决存活对象被标记成垃圾对象的,CMS收集器采用增量更新算法实现,G1收集器是通过原始快照(SATB)算法来实现的,具体细节可以参考本人的这篇博文JVM垃圾回收——三色标记法_jvm 三色标记_熟透的蜗牛的博客-CSDN博客。

        G1是一款并发回收的垃圾收集器,那么垃圾在回收时程序还继续运行,只要程序运行就会持续有新对象创建。G1为每个Region设计了两个名为TAMS(Top At Mark Start )的指针,把Region中的一部分空间划分出来,用于存储并发回收阶段新分配的对象,并发回收时新分配的对象的地址都必须在这两个指针位置以上,G1默认这个指针位置以上的对象都是隐式标记过的,默认他们是存活对象,不纳入本次回收的范围。与CMS中的“Concurrent Mode Failure”失败会导致Full GC 类似,如果回收速度赶不上分配速度,那么G1也要被迫冻结用户线程,进行Full GC而产生长时间的Stop The World。

3、G1如何建立可靠的停顿模型?

答:用户使用-XX:MaxGCPauseMills参数指定停顿时间,这个时间只是期望值,而不是说指定了200毫秒,就会在200毫秒内将垃圾回收完毕。G1收集器的停顿模型是以衰减均值为理论基础来实现的。在垃圾收集过程中,G1会记录每个Region的回收耗时,记忆集中脏卡数量等各个步骤的花费成本,然后统计出平均值,标准偏差、置信度等统计信息。然后可以计算回收那些Region,可以在期望的时间内达到最大的收益。

g1垃圾回收,JVM,jvm,java,G1

 初始标记:仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS指针的值,让下一阶段用户线程并发运行时,能够在Region上正确的分配对象。这个阶段需要STW,耗时很短,而且是借用MinorGC(上一轮垃圾回收时触发GC)时候同步完成的。

并发标记:从GC Roots 开始对堆中的对象进行可达性分析,递归扫描整个堆里的对象,这个过程耗时较长,但是是与用户线程并发执行的。对象扫描完之后还需要重新处理STAB记录下的在并发时有引用变动的对象。

最终标记:这个阶段也需要STW,用于处理并发阶段结束后仍然遗留下来的最后少量的STAB记录。

筛选回收:负责更新Region的统计数据,对各个Region的回收价值和成本排序,根据用户期望的停顿时间来执行回收计划,然后把决定回收的Region里的存活对象复制到空的Region,然后清空旧Region的空间。由于涉及到对象的移动,所以这个阶段也是需要STW的。

从上述可以看出,除了并发标记,其他阶段都是需要STW的,G1收集器不单单是追求低延迟的收集器,也衡量了吞吐量,所以在延迟和吞吐量之间做了一个权衡。

 四、G1收集器的优缺点

G1收集器一直都拿来和CMS垃圾收集器作比较,这里也用CMS垃圾收集器作对比。

  • 优势:因为CMS是基于标记-清除的算法实现的,所以CMS会有空间碎片化的问题。而在G1收集器上是不存在的,G1从整体上来看是基于标记-整理算法实现,从Region之间又是基于标记-复制算法实现的。
  • 由于G1不会产生空间碎片,可以为对象的分配提供更规整的内存。此外还避免了由于分配大对象时找不到连续的内存空间,而不得不提前触发下一次垃圾回收。
  • 不足:由于跨Region引用等大量双向卡表的存在,G1收集器比CMS(只需要处理老年代到新生代的引用)占用更多的内存。
  • CMS收集器使用写后屏障来更新维护卡表,而G1收集器除了使用写后屏障维护卡表,为了实现SATB的算法,还需要使用写前屏障来跟踪并发时指针变化情况。所以G1收集器会增加程序运行时的额外负载。

五、G1收集器的JVM参数配置

  • -XX:+UseG1GC  手动指定使用G1收集器执行内存回收任务(JDK9后不用设置,默认就是G1)。
  • -XX:G1HeapRegionSize  设置每个Region的大小。值是2的幂,范围是1MB到32MB之间,目标是根据最小的Java堆大小划分出约2048个区域。默认是堆内存的1/2000。
  • -XX:MaxGCPauseMillis  设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到)。默认值是200ms(如果这个值设置很小,如20ms,那么它收集的region会少,这样长时间后,堆内存会满。产生FullGC,FullGC会出现STW,反而影响用户体验)。
  • -XX:G1NewSizePercent  新生代的最小值默认是5%,此参数在实验阶段,如果想使用加-XX:+UnlockExperimentalVMOptions参数。
  • -XX:G1MaxNewSizePercent 新生代的最大值,默认值是60%,此参数在实验阶段,如果想使用加-XX:+UnlockExperimentalVMOptions参数。
  • -XX:ParallelGCThreads 设置STW时GC线程数的值。最多设置为8(垃圾回收线程)。
  • -XX:ConcGCThreads 设置并发标记的线程数。将n设置为并行垃圾回收线程数(ParallelGCThreads)的1/4左右。
  • -XX:InitiatingHeapOccupancyPercent  设置触发并发GC周期的Java堆占用率阈值。超过此值,就触发GC。默认值是45%。

测试代码

package com.wssnail.test;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 公众号 熟透的蜗牛
 * @version 1.0
 * @description: TODO
 * @date 2023/2/26 23:23
 */
public class TestG1 {
    private static String[] strArr = new String[]{"中国人民万岁", "梅西好样的,梅西好样的梅西好样的梅西好样的梅西好样的梅西好样的梅西好样的梅西好样的", "我爱看世界杯,我爱看世界杯我爱看世界杯我爱看世界杯我爱看世界杯我爱看世界杯我爱看世界杯我爱看世界杯我爱看世界杯"};

    public static void main(String[] args) {
        List<String[]> list = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(strArr);
        }
        while (true) {

        }
    }
}

JVM参数如下文章来源地址https://www.toymoban.com/news/detail-745158.html

-XX:+UseG1GC
-Xlog:gc*
-XX:G1HeapRegionSize=1
-XX:MaxGCPauseMillis=250
-XX:+UnlockExperimentalVMOptions
-XX:G1NewSizePercent=5
-XX:G1MaxNewSizePercent=60
-XX:ParallelGCThreads=2
-XX:+PrintCommandLineFlags

到了这里,关于JVM垃圾回收——G1垃圾收集器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【JVM】JVM收集器CMS与G1区别

    CMS收集器和G1收集器的区别 CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用 G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用 CMS收集器以最小的停顿时间为目标的收集器。 G1收集器可预测垃圾回收的停顿时间(建立可预测的停顿时间

    2024年02月08日
    浏览(81)
  • 从原理聊JVM(二):从串行收集器到分区收集开创者G1

    作者:京东科技 康志兴 随着Java的进化过程,涌现出各种不同的垃圾回收器,从串行执行到并行执行,从高吞吐到低延迟,终极目标就是让开发人员专注于程序的代码书写而无需关注内存管理。 JDK早期出现的垃圾回收器通常单独作用于不同分代,到后期出现的G1开始,才可以

    2023年04月24日
    浏览(34)
  • JVM-垃圾回收(标记算法,收集器)

    申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。 原资料地址:课程资料 垃圾回收的基本原理 1 什么是垃圾? 在内存中,没有被引用的对象就是垃圾。 2 如果找到垃圾对象? 引用计

    2024年02月21日
    浏览(52)
  • JVM垃圾回收算法和CMS垃圾收集器

    目录 判断一个对象是否死亡? 1、引用计数法  2、可达性分析算法 三色标记 垃圾收集算法 1、分代收集理论  2、垃圾回收算法 标记-清除 标记-复制 标记-整理 CMS(Concurrent Mark Sweep)收集器 CMS垃圾收集器步骤 CMS垃圾收集器优缺点 垃圾收集需要完成的三件事情: 哪些内存需

    2024年02月10日
    浏览(45)
  • 小研究 - 浅析 JVM 中 GC 回收算法与垃圾收集器

    本文主要介绍了JVM虚拟机中非常重要的两个部分,GC 回收算法和垃圾收集器。从可回收对象的标记开始,详细介绍 了四个主流的GC算法,详细总结了各自的算法思路及优缺点, 提出了何种情况下应该通常选用哪种算法。 目录 1 标记可回收对象 1.1 引用计数器 1.2 可达性分析

    2024年02月14日
    浏览(37)
  • 深入理解JAVA垃圾收集器CMS,G1工作流程原理 GC流程图 什么社会触发Minor GC?触发MinorGC过程。Full GC 过程。

    JVM内存空间基础知识点(基于JDk1.8) 1.方法区:逻辑概念,元空间,方法区主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。 2.程序计数器:程序计数器可以看作当前线程所执行的字节码的

    2024年04月25日
    浏览(39)
  • 【JVM】JVM垃圾收集器

    垃圾收集器是负责 执行垃圾回收的组件 ,它们用于 管理Java程序运行时的内存分配和释放 。垃圾收集器的主要任务是 自动回收不再使用的内存对象 ,并将 内存空间重新回收 以供程序继续使用。 Serial和Serial Old串行垃圾收集器,是指 使用单线程进行垃圾回收 ,堆内存较小,

    2024年02月13日
    浏览(41)
  • JVM 垃圾收集器

    重点:CMS,G1,ZGC 主要垃圾收集器如下,图中标出了它们的工作区域、垃圾收集算法,以及配合关系。 Serial 收集器 Serial 收集器是最基础、历史最悠久的收集器。 如同它的名字(串行),它是一个单线程工作的收集器,使用一个处理器或一条收集线程去完成垃圾收集工作。

    2024年02月10日
    浏览(45)
  • JVM的故事——垃圾收集器

    新生代收集器,最基础的收集器,单线程。进行垃圾收集时必须暂停其他所有工作线程,stop the world 新生代收集器,实质上是serial收集器的多线程版本。除了serial,只有它能和CMS收集器(老年代收集器)配合工作。随着处理器核心数越来越多,parnew比serial有着更好的性能。(但如

    2024年02月10日
    浏览(48)
  • 深入理解JVM垃圾收集器

    相关系列 深入理解JVM垃圾收集算法-CSDN博客 目前市面常见的垃圾收集器有Serial、ParNew、Parallel、CMS、Serial Old、Parallel Old、G1、ZGC以及有二种不常见的Epsilon、Shenandoah的,从上图可以看到有连线的的垃圾收集器是可以组合使用,是年轻代+老年代。为什么会出现这么多的垃圾收集

    2024年04月09日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包