G1垃圾回收

一、G1垃圾回收器

定义:
Garbage First(优先回收那些垃圾较多的区域以达到暂停时间短的目标)

JDK 9以后默认使用,而且替代了CMS 收集器
在这里插入图片描述
适用场景
● 同时注重吞吐量和低延迟(响应时间),默认的暂停目标是200ms
● 超大堆内存(内存大的),会将堆内存划分为多个大小相等的区域(每个区域差不多为1248M,每个区域都可以独立的作为伊甸园、幸存区、老年代)
● 整体上是标记+整理算法,两个区域之间是复制算法

相关参数:JDK8 并不是默认开启的,所需要参数开启
在这里插入图片描述

G1垃圾回收阶段(3个)

在这里插入图片描述

新生代伊甸园垃圾回收—–>内存不足(老年代内存超过预值),新生代回收+并发标记—–>回收新生代伊甸园、幸存区、老年代内存——>新生代伊甸园垃圾回收(重新开始)

① Young Collection

分区算法region
分代是按对象的生命周期划分,分区则是将堆空间划分连续几个不同小区间,每一个小区间独立回收,可以控制一次回收多少个小区间,方便控制 GC 产生的停顿时间

E:伊甸园 S:幸存区 O:老年代
● 会STW

【当类加载时,新创建的对象会分配到E(伊甸园)区,当其被逐渐占满会触发新生代垃圾回收】
在这里插入图片描述
【新生代垃圾回收将幸存的对象拷贝到幸存区(复制算法)】
在这里插入图片描述
【当幸存代区对象也较多时并且存活年龄超过一定时间会触发新生代垃圾回收,幸存区部分对象会晋升至老年代,将不够年龄的对象再次拷贝到另一个幸存区】
在这里插入图片描述

② Young Collection + CM

CM:并发标记(由根对象出发沿着引用链标记其他对象)

● 在 Young GC 时会对 GC Root 进行初始标记(找到根对象)
● 在老年代占用堆内存的比例达到阈值时,对进行并发标记,不会影响到用户的工作线程(不会STW),阈值可以根据用户来进行设定

-XX:InitiatingHeapOccupancyPercent=percent (默认45%)

在这里插入图片描述

③ Mixed Collection

会对E S O 进行全面的回收

● 最终标记
拷贝存活

-XX:MaxGCPauseMills:xxx 用于指定最长的停顿时间

【E区幸存对象会被复制到Survive区中,另一些Survive区中不够年龄的也会复制其中,符合晋升条件的对象会放入老年代中】===>属于新生代垃圾回收(发生在混合收集阶段)

【老年代区域经过并发标记阶段发现部分对象无用后同样采用复制算法将对象放入一个新的老年代区===>属于新生代垃圾回收】
在这里插入图片描述
:为什么有的老年代被拷贝了,有的没拷贝?

因为指定了最大停顿时间,如果对所有老年代都进行回收,耗时可能过高。为了保证时间不超过设定的停顿时间,会回收最有价值的老年代(回收后,能够得到更多内存)

Full GC(G1何时触发Full GC)
G1在老年代内存不足时(老年代所占内存超过阈值)

● 如果垃圾产生速度慢于垃圾回收速度,不会触发Full GC,还是并发地进行清理
● 如果垃圾产生速度快于垃圾回收速度,并发收集失败,退化为一个串行的收集(触发Full GC,与CMS相同)

Young Collection 跨代引用

● 新生代回收的跨代引用(老年代引用新生代)问题
在这里插入图片描述

● 卡表与Remembered Set(记录外部对它的引用)
———Remembered Set 存在于E中,用于保存新生代对象对应的脏卡
————脏卡:O被划分为多个区域(一个区域512K),如果该区域引用了新生代对象,则该区域被称为脏卡
好处 :在GC Root遍历时不用去找整个老年代,而是只需要关注脏卡对象(减小搜索范围,提高扫描根对象效率
● 在引用变更时通过post-write barried(写屏障)+ dirty card queue(异步操作)

● concurrent refinement threads 更新 Remembered Set
在这里插入图片描述

Remark

重新标记阶段
● pre-write barried + satb_mark_queue(在对象引用改变前将对象加入队列并表示其为未被处理的

在垃圾回收时,收集器处理对象的过程中

黑色已被处理,需要保留的
灰色正在处理中的
白色还未处理的

【并发标记阶段对象的处理状态】
在这里插入图片描述

但是在并发标记过程中,有可能A被处理了以后未引用C,但该处理过程还未结束,在处理过程结束之前A引用了C,这时就会用到remark

过程如下

● 之前C未被引用,这时A引用了C,就会给C加一个写屏障,写屏障的指令会被执行,将C放入一个队列当中,并将C变为 处理中 状态
● 在并发标记阶段结束以后,重新标记阶段会STW,然后将放在该队列中的对象重新处理,发现有强引用引用它,就会处理它
在这里插入图片描述

G1—垃圾回收器优化

其优化在持续进行中,以下为JDK8~JDK9的优化,更新的优化可参考Oracle官方文档

字符串去重

JDK 8u20 字符串去重

优点与缺点
● 节省了大量内存
● 新生代回收时间略微增加,导致略微多占用CPU

-XX:+UseStringDeduplication(开启字符串去重功能,默认打开)

String  s1=new String("hello");   //char[]{'h','e','l','l','o'}
String  s2=new String("hello");   //char[]{'h','e','l','l','o'}

过程
● 将所有新分配的字符串(底层是char[])放入一个队列
● 当新生代回收时,G1并发检查是否有重复的字符串
● 如果字符串的值一样,就让他们引用同一个字符串对象
● 注意,其与String.intern的区别
——intern关注的是字符串对象
——字符串去重关注的是char[]
——在JVM内部,使用了不同的字符串标

类卸载

JDK 8u40 并发标记类卸载
在所有对象经过并发标记结束后,就能知道哪些类不再被使用。如果一个类加载器的所有类都不在使用,则卸载它所加载的所有类(从8u40开始以后)

-XX:+ClassUnloadingWithConcurrentMark 默认启用

巨型对象

JDK 8u60 回收巨型对象
● 一个对象大于region的一半时,就称为巨型对象
● G1不会对巨型对象进行拷贝
● 回收时被优先考虑
● G1会跟踪老年代所有incoming引用,如果老年代incoming引用为0的巨型对象就可以在新生代垃圾回收时处理掉
在这里插入图片描述

动态调整阈值

JDK 9 并发标记起始时间的调整
● 并发标记必须在堆空间沾满前完成,否则退化为FullGC
● JDK 9 之前需要使用 -XX:InitiatingHeapOccupancyPercent
● JDK 9 可以动态调整
—— -XX:InitiatingHeapOccupancyPercent 用来设置初始值
—— 进行数据采样并动态调整
—— 总会添加一个安全的空挡时间

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
G1(Garbage First)垃圾回收器是一种低延迟的垃圾回收器,它可以在不影响应用程序吞吐量的情况下,有效地处理大量的内存垃圾。下面是G1垃圾回收器的执行流程: 1. 初始标记(Initial Mark):该阶段的目标是标记所有的根对象,并且标记从根对象直接可达的对象。为了达到这个目的,G1垃圾回收器会扫描所有的Java线程的栈,以及记录下所有的GC Root。 2. 并发标记(Concurrent Mark):在初始标记之后,G1垃圾回收器会开始并发的标记所有从根对象可达的对象。这是一个并发的过程,不会阻塞应用程序的执行。 3. 最终标记(Final Mark):在并发标记之后,G1垃圾回收器会再次暂停应用程序的执行,以完成所有未被标记的存活对象的标记。这个过程与初始标记是类似的。 4. 筛选回收(Live Data Counting and Evacuation):在最终标记之后,G1垃圾回收器会计算每个区域中存活的数据量。然后,它会选定一些区域作为回收集(Collection Set),将这些区域中的存活对象复制到空闲的区域中,并将这些区域标记为可回收的。 5. 清除(Cleanup):在筛选回收之后,G1垃圾回收器会开始清理所有被标记为可回收的区域。 需要注意的是,G1垃圾回收器是一个全局垃圾回收器,因此它不仅仅会处理单个堆区域的垃圾回收,而是会处理整个Java堆。同时,它还会根据应用程序运行的情况,动态地调整回收集的大小,以达到最佳的垃圾回收效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new一个对象_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值