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垃圾收集器也是基于分代收集理论设计的,但是它的堆内存的布局与其他垃圾收集器的布局有很明显的区别,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,可以在期望的时间内达到最大的收益。

初始标记:仅仅只是标记一下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参数如下
-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垃圾收集器
目录 一、什么是G1垃圾收集器 二、G1垃圾收集器的内存划分 三、G1垃圾收集器的收集过程 四、G1收集器的优缺点 五、G1收集器的JVM参数配置 一、什么是G1垃圾收集器 Garbage First(简称G1)收集器是垃圾收集器技术发展史上里程碑式的成果,它摒弃了传统垃圾收集器的…...
C语言深度剖析:关键字
C语言深度剖析:关键字C语言深度剖析:关键字前言定义与声明(补充内容)最宏大的关键字-auto最快的关键字-register关键字static被冤枉的关键字-sizeof整型在内存中的存储原码、反码、补码大小端补充理解变量内容的存储和取出为什么都是补码整型取值范围关于…...
聊一聊过度设计!
文章目录什么是过度设计?过度设计的坏处如何避免过度设计充分理解问题本身保持简单小步快跑征求其他人的意见总结新手程序员在做设计时,因为缺乏经验,很容易写出欠设计的代码,但有一些经验的程序员,尤其是在刚学习过设…...
程序员在小公司(没有大牛,人少)怎么成长?
大多数小公司都是创业公司,所以它们有着非常独特的“创业心态”。所谓创业心态通常表现为关注快速增长,竭尽所能让公司盈利,或者达成其他一些迫切目标。 在这样一家公司工作的软件开发人员,你极有可能要身兼多职,不能…...
【Fastdfs实战】在本地如何将文件上传到Linux虚拟机
作者:狮子也疯狂 专栏:《Fastdfs连续剧》 坚持做好每一步,幸运之神自然会驾凌在你的身上 目录一. 🦁 前言二. 🦁 上传原理Ⅰ. 🐇 原理图解Ⅱ. 🐇 传输原理三. 🦁 实战演示Ⅰ. &…...
ERP 系统的应用对企业财务会计信息系统内部控制的影响
(一)对企业的财务信息数据进行实时和动态管理传统的财务会计信息系统一般都是采用单一的软件系统,所以在信息的传递及处理上常常不能满足企业的需要,信息与其他部门存在不对称及滞后的现象。而ERP 系统是通过有效的技术手段将企业的各种分散的数据进行完…...
智慧物联网源码带手机端源码 物联网系统源码
在智慧工厂领域,智慧城市领域,都需要对设备进行监控。比如工厂需要对周围环境温度、湿度、气压、电压,灯的开关进行监控。这时候就需要物联网平台来进行管理。 推荐一个基于java开发的物联网平台,前端HTML带云组态、可接入视频监…...
AI绘画进军三次元,有人用它打造赛博女友?(diffusion)
目录0 写在前面1 AI绘画技术飞跃2 效果展示3 环境配置3.1 下载基础模型3.2 更新.NET和模型3.3 下载绘画模型3.4 启动项目3.5 标签配置4 结语0 写在前面 机器学习强基计划聚焦深度和广度,加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理&a…...
计算机网络高频知识点
目录 一、http状态码 二、浏览器怎么数据缓存 三、强缓存与协商缓存 1、强缓存 2、协商缓存 四、简单请求与复杂请求 五、PUT 请求类型 六、GET请求类型 七、GET 和 POST 的区别 八、跨域 1、什么时候会跨域 2、解决方式 九、计算机网络的七层协议与五层协议分别指…...
谈谈前端性能优化-面试版
前言 当我们去面试的时候,很大概率会被面试官问这么一个问题:你有尝试过对项目做性能优化吗?或者你了解哪些性能优化的方法?听到这个问题的你可能是这样的: 似曾相识但又说不清楚,往往只能零散地说出那么几…...
JAVA连接数据库——JDBC的简单使用
JDBC即Java数据库连接.用来实现Java程序对数据库增删查改。 为了对接Java程序和数据库,java.sql提供了很多api包含在java.sql和javax.sql里面 结构: DriverManager接口: 每一个数据库的驱动程序都必须去到DriverManager注册,生成一个Connection Conn…...
Pandas数据查询
Pandas数据查询 Pandas查询数据的几种方法 df.loc方法,根据行、列的标签值查询 df.iloc方法,根据行、列的数字位置查询 df.where方法 df.query方法 .loc既能查询,又能覆盖写入,强烈推荐! Pandas使用df.loc查询数据…...
NLP-统计词频之处理停用词
前言 本文是该专栏的第1篇,后面会持续分享NLP的各种干货知识,值得关注。 一般来说,自然语言处理(NLP)就是开发能够理解人类语言的应用程序或者应用服务。 举个例子,如Facebook News Feed这种社交网站推送,它的算法知道你的兴趣是自然语言处理,就会推送相关的广告或者…...
sort 定制排序规则(配合functools.cmp_to_key())
sort 定制排序规则(配合functools.cmp_to_key()) 配合例题学习 题目链接:179. 最大数 题目大意:给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。 注意&a…...
【华为OD机试模拟题】用 C++ 实现 - 内存池(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明内存池题目输入输出示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:…...
Python--深入浅出的装饰器--1
本章一起深入浅出一下装饰器。前面我们讲过一章装饰器了。不知道各位看懂了多少。每太看懂也没关系,本章就一起实操一下。简单的例子例1例2上述的两个例子,执行结果为:1423.为什么呢???解析语法糖ÿ…...
如何从0创建Spring Cloud Alibaba(多模块)
以一个父工程带两个Module(test1、test2)为例。 一、创建父工程 由于是模块化项目,那么父工程不需要实际的代码逻辑,因此无需创建src,那么可以有几种方式创建,例如: 使用Spring Initializr脚…...
【华为OD机试模拟题】用 C++ 实现 - 某公司组织招聘(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明招聘 | 某公司组织题目输入输出示例一输入输出说明示例二输入输出说明示例三输入输出说明...
Spring Cloud Sentinel实战(一)- Sentinel介绍
Sentinel介绍 什么是Sentinel 分布式系统的流量防卫兵:随着微服务的普及,服务调用的稳定性变得越来越重要。Sentinel以“流量”为切入点,在流量控制、断路、负载保护等多个领域开展工作,保障服务可靠性。 特点: 1. 2…...
基于SpringBoot的任务管理三种方式
文章目录前言一,异步任务1.1 无返回值异步任务调用1.2 有返回值异步任务调用二、定时任务2.1 背景介绍2.2 todo三、邮箱任务3.1 todo前言 开发 web 应用时,多数应用都具备任务调度功能,常见的任务包括异步任务、定时任务和邮件任务。我们以数…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
