当前位置:网站首页>JVM学习----垃圾回收--G1
JVM学习----垃圾回收--G1
2022-08-02 03:15:00 【北海怪兽Monster】
Garbage First
2004论文发布 ----> 2009 JDK 6u14 体验 ----> 2012 JDK 7u4 官方支持 ----> 2017 JDK9 默认
适用场景:
- 同时注重吞吐量和低延时,默认的暂停目标200ms
- 超大堆内存,会将堆划分为多个大小相等Region
- 整体上是标记整理算法,两个区域之间是复制算法
相关JVM参数:
-XX:+UseG1GC
-XX:G1HeapRegionSize=size
-XX:MaxGCPauseMillis=time
G1 垃圾回收阶段
G1三个循环回收阶段

1、Young Collection (新生代)
会STW
1)、将内存换分为多个区域,E代表Eden
2)、当Eden区域逐渐被占满,触发 Minor GC,采用复制算法,将幸存的对象复制到幸存区。S:代表幸存区。
3)、在经过一段时间之后,幸存区逐渐被占满,那么将年龄够的对象晋升到老年代。将不符合年龄要求的对象,拷贝到新的幸存区。
2、Young Collection + CM
在Young GC时会进行GC Root的初始标记(找到根对象,STW时进行,在上一个阶段执行)
老年代占用堆空间比例达到阈值时,会进行并发标记(根据根对象的引用链,找到其他对象,不会STW),由下面的JVM参数决定
-XX:InitiatingHeapOccupancyPercent=percent ( 默认45% )
3、Mixed Collection
会对 E、S、O 进行全面的垃圾回收
最终标记(Remark)会STW,因为并发标记可能有遗漏
拷贝存活(Evacuation)会STW
-XX:MaxGCPauseMillis=ms (最大暂停时间)
对于新生代,将Eden区的幸存对象拷贝到幸存区,将其他幸存区里面的对象,该晋升的晋升,该继续保留的保留。其他的就全部进行回收了。
对于老年代,因为老年代会很大,默认45%,那么根据我们最大暂停时间,可能在这设置的时间内,我们不能讲全部老年区进行判断回收,那么系统就会判断,那么回收等级高,就优先回收哪些优先等级高的。
Full GC

CMS,在碎片少的时候,是并发执行垃圾回收的,如果要是并发失败,会退化为 Serial GC,那么这种产生的GC 才叫Full GC
G1 ,当你垃圾产生的速度 小于 垃圾回收的速度,这不叫Full GC。 当你垃圾产生的速度 大于 垃圾回收的速度,才会产生 Full GC,并发回收失败,进行并行回收。
Young Collection 跨代引用问题
新生代回收的跨代引用(老年代引用新生代)问题
当新生代对象被老年代对象引用,我们将老年代再进行细分,每个大约512k大小。使用卡表技术
如果这个老年代引用了新生代对象,那么这个卡,我们就标记为脏卡。以后我们就不用遍历整个老年代,减少搜索范围,提高GC Root的寻找效率。
新生代会记录脏卡,那么在 新生代垃圾回收时,就会根据Eden记录脏卡区域进行遍历查询GC Root
Remark 重新标记
在并发标记过程中,产生了新的引用,原本应该被回收的对象被引用了。但是并发标记并没有对 被引用的对象进行重新标记。
所以重新标记就是为了解决这种情况。
具体做法,在并发标记时:当对象引用 发生改变时,JVM就会对该对象加入一个 写屏障 (只要对象引用发生了改变,就会触发写屏障)。
写屏障:会将该对象加入一个队列(satb_mark_queue队列)之中,将该对象变为正在处理中的状态,进入重新标记阶段。
重新标记,会STW,将队列中的 对象取出来,进行再一次的判断出来,判断队列中的对象是回收还是保留。
G1 垃圾回收器的优化(8->9的优化)
JDK 8u20 字符串去重
优点:节省大量内存
去电:略微多占用cpu时间,新生代回收时间略微增加
-XX:+UserStringDeduplication
jdk8 中字符串的存储底层实际采用的char数组进行存储,new两个,那么也是存两个char数组
String s1 = new String("hello"); // char[]{'h','e','l','l','o'}
String s2 = new String("hello"); // char[]{'h','e','l','l','o'}
- 将所有新分配的字符串放入一个队列
- 当新生代回收时,G1并发检查是否有字符串重复
- 如果它们值相同,让它们引用同一个char[] // 例如上面代码,s1,s2 引用同一个
- 主义,与String.intern() 不一样
- String.intern() 关注的是字符串对象 // 用的StringTable去重,是用的常量池,这个针对的是对象
- 而字符串去重关注的是char[]
- 而JVM内部,使用了不同的字符串表
JDK 8u40 并发标记类卸载
所有对象都经过并发标记后,就能知道哪些类不再被使用,当一个类加载器的所有类都不再被使用,则卸载它所加载过的所有类。
例如,很多框架都是用自定义加载器。
-XX:+ClassUnloadWithConcurrentMark // 默认启用
JDK 8u60 回收巨型对象
- 一个对象大于region的一半时,称之为巨型对象(你也可以占多个region)
- G1不会对巨型对象进行拷贝
- 回收时,巨型对象优先考虑
- G1会跟踪老年代所有incoming引用,这样老年代incoming引用为0的巨型对象就可以在新生代垃圾回收时处理掉。
JDK 9 并发标记起始时间的调整
- 并发标记必须在堆空间占满前完成,否则退化为FullGC
- JDK 9 之前需要使用 -XX:InitiatingHeapOccupancyPercent
- JDK 9 可以动态调整
- -XX:InitiatingHeapOccupancyPercent 用来设置初始值,默认45%
- 进行数据采用并动态调整 — > 阈值
- 总会添加一个安全的空档空间
这样可以尽可能避免 G1 GC 退化为 FullGC
边栏推荐
猜你喜欢

Difference between #{} and ${}

MySQL8.0.26 installation and configuration tutorial (windows 64-bit)

5. Hezhou Air32F103_LCD_key

WebShell Feature Value Summary and Detection Tool

Webshell upload method

STM32——LCD—TFTLCD原理与配置介绍

利用WebShell拿Shell技巧

01-Node-Express系统框架搭建(express-generator)

MySQL中的存储过程(详细篇)

# ODS及DWD层自动化构建##, 220731,
随机推荐
Heao Technology Network Interview (with reference answers)
运维理想和现实,你是?
MySQL中的时区设置
MySQL8--Windows下使用压缩包安装的方法
7-43 字符串关键字的散列映射 (25 分) 谜之测试点
PHP WebShell Free Kill
Ribbon本地实现负载均衡
ASP WebShell 后门脚本与免杀
mysql8.0.28 download and installation detailed tutorial, suitable for win11
bgp机房的动态路由和静态路由的区别
2022.7.30 js notes Operators and flow controllers, loops
Double Strings (don't always forget substr)
MySQL8.0.28安装教程
MySQL中根据日期进行范围查询
7-40 奥运排行榜 (25 分)多项排序
CV-Model [4]: MobileNet v3
基于时延估计的动力型下肢假肢分段控制策略研究
线性代数学习笔记2-1:向量和向量组、线性相关性(张成空间的概念)
STM32——LCD—TFTLCD原理与配置介绍
MySQL8 -- use msi (graphical user interface) under Windows installation method