【JVM】—深入理解G1回收器—回收过程详解

news/2024/10/23 10:32:57/

深入理解G1回收器—回收过程详解

⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐

如果可以,麻烦各位看官顺手点个star~😊

文章目录

  • 深入理解G1回收器—回收过程详解
    • 1 与CMS回收过程做比较
    • 2 G1垃圾回收过程详解
    • 3 全局并发标记Global concurrent marking
    • 4 拷贝存活对象Evacuation


关于G1相关概念请参考【JVM】—深入理解G1回收器——概念详解

1 与CMS回收过程做比较

从名字中的Mark Sweep这两个词可以看出,CMS 收集器是一种 标记-清除”算法实现的,它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:

  • 初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快 ;
  • 并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。
  • 重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
  • 并发清除: 开启用户线程,同时 GC 线程开始对未标记的区域做清扫。
    在这里插入图片描述

2 G1垃圾回收过程详解

G1 收集器的运作大致分为以下几个步骤:

  • 初始标记:这是一次SWT事件。对于G1正常的年轻代 GC 上。标记可能引用老生代对象的新生代区域(引用根区域);
  • 并发标记: 在整个堆中查找活动对象,与应用线程并行,此阶段可能会被新生代GC中断;
  • 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。
  • 筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

在这里插入图片描述

G1收集可以分为两大部分:

  • 全局并发标记(global concurrent marking);
  • 拷贝存活对象(evacuation),或者叫迁移;

3 全局并发标记Global concurrent marking

标记老年代region,提供统计结果供Mixed GC使用,选取收益高的老年代region回收,帮助回收老年代对象。

关于G1相关概念请参考【JVM】—深入理解G1回收器——概念详解

Global concurrent marking基于SATB形式的并发标记,分为以下几个阶段:

  1. The Initial Mark Phase(STW):扫描GC roots直接可达对象,并将他们的字段压入扫描栈(marking stack)等待后续扫描。初始标记阶段借用young gc的暂停,没有额外的单独暂停阶段,所以在The Initial Mark Phase发生在young gc之后。

在这里插入图片描述

  1. The Concurrent Marking Phase:从扫描栈(marking stack)中递归查找所有引用可达对象。和用户线程并行执行。

在这里插入图片描述

  1. The Remark Phase(STW):完成存活对象的标记,标记那些在并发标记阶段发生变化的对象,将被回收。

在这里插入图片描述

  1. The Cleanup Phase (STW and Concurrent):old region存活对象情况统计(确定未使用region和Mixed GC收集候选region)(Stop the world);将空闲region重置到空闲列表中(concurrent);

在这里插入图片描述

最终所选区域已被收集并压缩为图中所示的深蓝色区域和深绿色区域:

在这里插入图片描述

4 拷贝存活对象Evacuation

关于G1相关概念请参考【JVM】—深入理解G1回收器——概念详解

Evacuation阶段是全暂停的。它负责把一部分region里的活对象拷贝到空region里去,然后回收原本的region的空间。Evacuation阶段可以自由选择任意多个region来独立收集构成CSet),考RSet实现。这是regional garbage collector的特征。

G1有两种GC模式:Young GC和Mixed GC,Young GC和Mixed GC都是STW。

  • Young GC:选定所有年轻代region添加到CSet中。通过控制年轻代region的个数来,即年轻代内存的大小,来控制young GC的时间开销。
  • Mixed GC:选定所有年轻代region,外加根据global concurrent marking统计结果得出的收益高的若干老年代region添加到CSet中。在用户指定开销返回内尽可能选择收益高的老年代region。

在选定CSet后,Evacuation其实就跟ParallelScavenge的Young GC的算法类似,采用并行copying(或者叫scavenging)算法把CSet里每个region里的活对象拷贝到新的region里,整个过程完全暂停。从这个意义上说,G1的Evacuation跟传统的标记整理算法的compaction完全不同:前者会自己从根集合遍历对象图来判定对象的生死,不需要依赖全局并发标记的结果(有就用没有拉倒);而后者则依赖于之前的mark阶段对对象生死的判定。

CSet的选定完全靠统计模型找处收益最高、开销不超过用户指定的上限的若干region。由于每个region都有RSet覆盖,要单独evacuate任意一个或多个region都没问题。

可以看到young gen region总是在CSet内。因此分代式G1不维护从young gen region出发的引用涉及的RSet更新。Mixed GC不是Full GC,因为Mixed GC只收集部分老年代region,如果在Mixed GC期间出现老年代被占用完的情况,JVM会采用Serial Old(Full GC)收集器来收集整个Heap。

老年代region回收完全依赖于Mixed GC。G1的正常工作流程就是在Young GC和Mixed GC之间视情况切换,背后定期做global concurrent marking(全局并发标记),global concurrent marking(全局并发标记)主要是为Mixed GC提供标记服务,而不是一次GC过程中的必须环节。G1的所有concurrent动作都在global concurrent marking里。Young GC和Mixed GC都是完全暂停的。

Young GC 和Mixed GC都是STW,为什么G1还可以被称为低延迟的GC实现呢?

可以看到在这么多步骤里,G1只有两件事是并发执行的:(1) 全局并发标记;(2) logging write barrier的部分处理。而“拷贝对象”(evacuation)这个很耗时的动作却不是并发而是完全暂停的。那G1为何还可以叫做低延迟的GC实现呢?

重点就在于G1虽然会mark整个堆,但并不evacuate所有有活对象的region;通过只选择收益高的少量region来evacuate,这种暂停的开销就可以(在一定范围内)可控。每次evacuate的暂停时间应该跟一般GC的young GC类似。所以G1把自己标榜为“软实时”(soft real-time)的GC。


http://www.ppmy.cn/news/1541301.html

相关文章

pycharm配置git版本控制

今天记录一下如何在pycharm工具中配置git版本控制,主要分以下步骤: 1、安装git 首先需要有git环境,去git官网下载git安装包,下一步下一步执行安装完成即可 2、在pycharm中配置git路径 下载git后,在pycharm的 setti…

Android 拦截第三方推送的通知消息或系统消息或通知栏

在需求开发中,我们需要做到各种通知的屏蔽,系统的通知,下拉状态栏通知,第三方应用通知,前后台通知。以下是收集所有相关屏蔽和拦截、取消、隐藏,过滤等消息信息的方法尝试,根据不同需要定制修改,相信总有一个是可以做到的。 根据应用包名来实现对特定APP前台通知的屏蔽…

16. Redis异步队列

一、 安装组件 composer require hyperf/async-queue二、 配置文件 位置:config/autoload/async_queue.php如文件不存在 ,可通过 php bin/hyperf.php vendor:publish hyperf/async-queue 命令来发布。return [default => [driver => Hyperf\AsyncQueue\Driver\RedisDr…

C++ —— 实现一个日期类

目录 一. 对日期类的介绍 二. 实现日期类 1. 运算符重载 2.日期类实现代码 一. 对日期类的介绍 通过对类和对象(这里链接是类和对象的介绍)的学习,类就是一种模型一样的东西,是对象一种抽象的描述。所以实现日期类&#xff0…

如何做设备管理系统?六大亮点功能与八大关键指标?

在当今企业运营中,设备管理面临着诸多挑战。 领导不重视管理,使得设备管理缺乏战略层面的支持和资源投入;设备超负荷运转,不仅影响设备寿命,还增加了故障风险;管理方式陈旧,无法适应现代企业高…

JAVA接口,继承,和抽象类的使用

特点: 接口是行为的契约,定义了类必须实现的能力。可以用于多继承。抽象类是具有部分实现的类,需要通过继承来具体化某些行为。继承用于复用父类的实现,增强代码的扩展性和可维护性。 在Java中,接口、继承和抽象类都…

马拉车算法(C/C++)

#1024程序员节 | 征文# 马拉车算法(Manachers Algorithm)是一种用于在字符串中查找最长回文子串的线性时间复杂度算法。该算法由Udi Manacher在1980年代提出,因此得名。它的核心思想是利用已知的回文信息来减少不必要的比较,从而提…

Java | Leetcode Java题解之第502题IPO

题目&#xff1a; 题解&#xff1a; class Solution {public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) {int n profits.length;int curr 0;int[][] arr new int[n][2];for (int i 0; i < n; i) {arr[i][0] capital[i];arr[i][1] profi…