JVM-G1

G1是一种服务端应用使用的垃圾收集器,目标是用在多核、大内存的机器上,它在大多数情况下可以实现指定的GC暂停时间,同时还能保持较高的吞吐量

原来在物理上都是两块连续的内存(新生代和老年代),每一次的操作都是在大的空间里面执行,大内存里面再怎么提升也提升不了多少,所以G1使用了不一样的内存布局,借助了分而治之的思想

它把内存分为一个一个的Region,大小为1M、2M、2的次方最大到32M,每一份Region在逻辑上依然属于某一个分代,这个分代分为四种,第一种Old区都是放老对象的、Survivor区放存活对象的、Eden区放新生对象的、Humongous区大对象区域,对象特别大有可能会跨两个reguion。

每个分区都可能是年轻代也可能是老年代,但是在同一时刻只能属于某个代。年轻代、幸存代、老年代这些概念还存在,成为逻辑上的概念,这样方便复用之前分代框架的逻辑。在物理上不需要连续,则带来了额外的好处----有的分区内垃圾对象特别多,有的分区内垃圾对象很少,G1会优先回收垃圾对象特别多的分区,这样可以花费较少的时间来回收这些分区的垃圾,这也就是G1名字的由来,即首先收集垃圾最多的分区。新生代其实并不是使用与这种算法的,依然是在新生代满了的时候,对整个新生代进行回收----整个新生代中的对象,要么被回收、要么晋升,至于新生代也采取分区机制的原因,则是因为这样跟老年代的策略统一,方便调整代的大小。G1还是一种带压缩的收集器,在回收老年代的分区时,是将存活的对象从一个分区拷贝到另外一个可用分区,这个拷贝的过程就实现了局部的压缩。每个分区的大小从1M到32M不等,但是都是2的幂次方。

 G1的内存区域是很灵活的,某块内存是Eden区,在进行一次YGC之后把这个Eden区擦除了,下次可能就把它当old区使用。

基本概念

card table

在新生代里面有很多对象,老年代也有很多对象,怎么确定对象是否存活呢?可以通过根对象找到,但是如果根对象已经在old区,那么就要遍历整个old区,old区很大,总不能每一次YGC都要遍历一次old区,这个时候就需要cardtable了。

对象存在一个一个的card里面,如果old区有对象指向了young区则Bitmap将这个card标记为Dirty,下次扫描只需扫描Dirtycard

 

CSet

  • CSet=Collection Set
  • 一组可被回收的分区集合。在CSet中存活的数据会在GC过程中被移动到另一个可用分区,CSet中的分区可以来自Eden区、survivor空间、或者老年代。CSet会占用不到整个堆空间的1%大小
  • 其实就是记录那些需要接下来回收的card,回收线程需要回收的时候去哪里找?去CSet里面

Rset

每一个Region里面都有一个哈希表,里面记录着其他Region中对象到本对象的引用,这个是G1高速回收的关键,也是后面三色标记的关键,只要有Rset就可以找到有没有对象指向,没有的话就可以回收。

 G1新老年代比例

5% - 60%
– 一般不用手工指定
– 也不要手工指定,因为这是G1预测停顿时间的基准

这个由G1自动调整,如这次STW的时间为200ms,比预期的时间长的话,G1会自动将Y区的大小调小,G1会跟踪每一次停顿时间

G1的GC何时触发

▪ YGC
Eden空间不足
多线程并行执行
▪ FGC
Old空间不足
System.gc()

使用的是Serial

G1产生FGC如何解决

▪ 扩内存
▪ 提高CPU性能(回收的快,业务逻辑产生对象的速度固定,垃圾回收越快,内存空间越大)
▪ 降低MixedGC触发的阈值,让MixedGC提早发生(默认是45%)
MixedGC就比如YGC不行了,对象产生特别多到45%,占堆内存的空间超过45%,默认就启动MixedGC,Y区和O区都要MixedGC,这个值是可以自己定的,MixedGC相当于一套完整的CMS。

MixedGC

G1的YGC不行了,对象产生得特别多已经超过了堆内存的45%,这个时候就要进行MixedGC,当然达到多少进行MixedGC是可以通过参数进行设置的

G1的GC主要有两种:YGCMixedGC

G1也会有FGC,而且JDK10以前都是串行的,之后才是并行。我们说G1和CMS调优目标其中之一叫做FGC尽量别有。

 过程:

▪ 初始标记 STW
▪ 并发标记
▪ 最终标记 STW (重新标记)
▪ 筛选回收 STW (并行),和CMS不同的是他有一个筛选的过程,筛选垃圾比较多的Region,把Region里面存活的对象复制到一个新地方进行压缩,然后回收这个Region

并发标记算法

G1也好,CMS也好,他们最核心的在于并发标记,一边干活一边标记,难点在于在标记对象安定过程中,对象的引用关系正在发生改变,CMS和G1使用的标记算法都是三色标记法

三色标记

 漏标:漏标有两个条件缺一不可

  • 标记进行时增加了一个黑到白的引用,如果不重新对黑色进行处理,则会漏标
  • 标记进行时删除了灰对象到白对象的引用,那么这个白对象有可能被漏标

解决漏标:打破两个条件即可

  • incremental update – 增量更新,关注引用的增加,把黑色重新标记为灰色,下次重新扫描属性,CMS使用;
  • SATB snapshot at the beginning – 关注引用的删除当B->D消失时,要把这个引用推到GC的堆栈,保证D还能被GC扫描到;G1使用。这个配合Rset使用,当扫描堆栈的时候,会去扫描D中的cardtable,发现他的Rset里面有A->D的就不会把他当成垃圾。

为什么G1用SATB?

灰色 → 白色 引用消失时,如果没有黑色指向白色,引用会被push到堆栈
下次扫描时拿到这个引用,由于有RSet的存在,不需要扫描整个堆去查找指向白色的引用,效率比较高.SATB 配合 RSet ,浑然天成

 

 RSet和赋值效率

  • 由于RSet的存在,再每次给对象赋引用的时候,就要做些额外的操作
  • ☞再RSet中做一些额外的记录(GC中称之为写屏障)
  • 这个写屏障不等于前面讲的内存屏障

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值