乐趣区

关于java:不管卷不卷面试还是得问问你G1原理

所有的垃圾回收器的目标都是朝着缩小 STW 的目标而后退,G1(Garbage First)回收器的呈现颠覆了之前版本 CMS、Parallel 等垃圾回收器的分代收集形式,从 2004 年 Sun 公布第一篇对于 G1 的论文后,直到 2012 年 JDK7 公布更新版本,花了将近 10 年的工夫 G1 才达到商用的水平,而到 JDK9 公布之后,G1 成为了默认的垃圾回收器,CMS 也变相地相当于被淘汰了。

G1 构造

G1 摈弃了之前的分代收集的形式,面向整个堆内存进行回收,把内存划分为多个大小相等的独立区域 Region。

一共有 4 种 Region:

  1. 自在分区 Free Region
  2. 年老代分区 Young Region,年老代还是会存在 Eden 和 Survivor 的辨别
  3. 老年代分区 Old Region
  4. 大对象分区 Humongous Region

每个 Region 的大小通过 -XX:G1HeapRegionSize 来设置,大小为 1~32MB,默认最多能够有 2048 个 Region,那么依照默认值计算 G1 能治理的最大内存就是 32MB*2048=64G。

对于大对象的存储,存在 Humongous 概念,对 G1 来说,超过一个 Region 一半大小的对象都被认为大对象,将会被放入 Humongous Region,而对于超过整个 Region 的大对象,则用几个间断的 Humongous 来存储(如下图 H 区域)。

G1 劣势

下面咱们也提到,垃圾回收器的最终目标都是为了缩小 STW 造成的进展,比方之前老的垃圾回收器 CMS 这种带来的进展工夫是不可预估的。

而 G1 最大的劣势就在于 可预测的进展工夫模型 ,咱们能够本人通过参数-XX:MaxGCPauseMillis 来设置容许的进展工夫 (默认 200ms),G1 会收集每个 Region 的回收之后的空间大小、回收须要的工夫,依据评估失去的价值,在后盾保护一个优先级列表,而后基于咱们设置的进展工夫优先回收 价值收益最大 的 Region。

那么,这个可预测的进展工夫模型怎么计算和建设的?次要是基于 衰减平均值 的实践根底,衰减均匀是一种数学方法,用来计算一个数列的平均值,给近期的数据更高的权重,强调近期数据对后果的影响,代码如下:

hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp
double get_new_prediction(TruncatedSeq* seq) {return MAX2(seq->davg() + sigma() * seq->dsd(),
              seq->davg() * confidence_factor(seq->num()));
}

davg示意衰减值

sigma示意一个系数,代表信贷度,默认值为 0.5

dsd示意衰减标准偏差

confidence_factor示意可信度系数,用于当样本数据有余 (小于 5 个) 时取一个大于 1 的值,样本数据越少该值越大。

基于这个模型,G1 心愿依据用户设置的进展工夫(只是冀望工夫,尽量致力在这个范畴内实现 GC)来抉择须要对哪些 Region 进行回收,能回收多大空间。

比方过来 10 次回收 10G 内存破费 1s,如果预设的进展工夫是 200ms,那么就最多能够回收 2G 的内存空间。

空间调配 & 扩大

既然 G1 还是存在新生代和老年代的概念,那么新生代和老年代的空间是怎么划分的呢?

在 G1 中,新增了两个参数 G1MaxNewSizePercentG1NewSizePercent,用来管制新生代的大小,默认的状况下G1NewSizePercent 为 5,也就是占整个堆空间的 5%,G1MaxNewSizePercent默认为 60,也就是堆空间的 60%。

假如当初咱们的堆空间大小是 4G,依照默认最大 2048 个 Region 计算,每个 Region 的大小就是 2M。

初始新生代的大小那么就是 200M,大概 100 个 Region 格子,动静扩大最大就是 60%*4G=2.4G 大小。

不过显然,事件不是这么简略,实际上初始化新生代的空间大小逻辑还是挺简单的。

首先,咱们通过原有参数 -Xms 设置初始堆的大小,-Xmx设置最大堆的大小还是失效的,能够设置堆的大小。

  1. 能够通过原有参数 -Xmn 或者新的参数 G1NewSizePercentG1MaxNewSizePercent 来设置年老代的大小,如果设置了 -Xmn 相当于设置G1NewSizePercent=G1MaxNewSizePercent
  2. 接着看是不是设置了 -XX:NewRatio(示意年老代与老年代比值,默认值为 2,代表年老代老年代大小为 1:2),如果1 都设置了,那么疏忽 NewRatio,反之则代表G1NewSizePercent=G1MaxNewSizePercent,并且调配规定还是依照NewRatio 的规定。
  3. 如果只是设置了 G1NewSizePercentG1MaxNewSizePercent 中的一个,那么就依照这两个参数的默认值 5% 和 60% 来设置。
  4. 如果设置了-XX:SurvivorRatio,默认为 8,那么 Eden 和 Survivor 还是依照这个比例来调配

依照这个规定,咱们新生代和老年代的空间调配根本就实现,如果说新生代走默认的规定,每次动静扩大空间大小怎么办?

有一个参数叫做 -XX:GCTimeRatio 示意 GC 工夫与利用消耗工夫比,默认为 9,就是说 GC 工夫和利用工夫占比超过 10% 才进行扩大,扩大比例为 20%,最小不能小于 1M。

回收过程

G1 的回收过程分为以下四个步骤:

  1. 初始标记:标记 GC ROOT 能关联到的对象,须要 STW
  2. 并发标记:从 GCRoots 的间接关联对象开始遍历整个对象图的过程,扫描实现后还会重新处理并发标记过程中产生变动的对象
  3. 最终标记:短暂暂停用户线程,再解决一次,须要 STW
  4. 筛选回收:更新 Region 的统计数据,对每个 Region 的回收价值和老本排序,依据用户设置的进展工夫制订回收打算。再把须要回收的 Region 中存活对象复制到空的 Region,同时清理旧的 Region。须要 STW。

总的来说这是一个偏差记忆的回收过程,晓得就行了。

绝对于之前咱们存在分代概念的 GC 来说,G1 其实也是相似的过程,总体能够分为这两种:

  1. 年老代 GC,年老代 Region 在超过咱们默认设置的最大大小之后就会触发 GC,还是用的咱们相熟的复制算法,Eden 和 Survivor 来回倒腾,这里不再赘述。
  2. Mixed GC 混合回收,混合回收相似于之前咱们的 Full GC 概念,既会回收年老代的 Region,也会回收老年代的 Region,还有咱们新的 Humongous 大对象区域。触发规定依据参数 -XX:InitiatingHeapOccupancyPercent(默认 45%) 值,也就是说老年代 Region 达到整个堆内存的 45% 时触发 Mixed GC。

其余问题

下面应该把基本概念都解释完了。

比方什么是 G1?G1 有什么特点?他的长处是什么?划分 Region 后怎么调配空间?怎么进行垃圾回收?什么时候进行 YGC?什么时候进行 FGC?牢靠的进展工夫模型建设形式?

除此之外,其实还有一些较为简单的问题,比方之前咱们说分代收集有跨代援用的问题,划分 Region 之后应该也有对不对,那怎么解决的?

还有之前咱们说并发收集阶段怎么解决用户线程和收集线程互不烦扰的?

这些更深一点的问题其实在当初曾经卷到须要问三色标记了吗?曾经说到了很多了,上面咱们再具体点阐明下在 G1 中的一些不同点。

记忆集

在这篇文章中咱们提到过一次对于 Remembered Set 的概念,为了防止 GC 时扫描整个堆内存,用来标记哪些区域存在跨代援用,对于 G1 来说也一样,只不过 G1 的记忆集会更简单一点。

每个 Region 中都存在一个 Hash Table 构造的记忆集,Key 为其余 Region 的起始地址,Value 是其余 Card Table 卡表的索引汇合。

原来咱们的卡表指向的是卡页的内存地址段,代表我援用了谁,当初的记忆集则是代表着谁援用了我,因而收集的过程会更简单一点,并且须要额定的 10%~20% 的堆内存空间来维持。

保护记忆集的形式也和卡表相似,通过 写屏障 来实现。

原始快照 SATB

在三色标记中咱们也提到过,并发标记用户线程和收集线程一起工作会产生问题,解决方案 CMS 应用的是增量更新,G1 则是用原始快照。

总结

写这些货色比拟吃力,因为总在想在了解的根底上怎么写的更通俗易懂,然而发现如同并不容易,因为本人也都是看完没过多久就遗记了,所以记录下来,能看懂就行了,切实不行就去看书。

周老师的深刻 Java 虚拟机写的比较简单,很多货色要去搜材料和书联合看能力看明确,另外一本书写的也不是很好,作者感觉只是堆砌知识点,看起来很吃力,美团写的那篇文章也是一大堆名词,不晓得的人看的几乎蛋疼。

我应该,比他们写的更艰深一点就好了?

参考:

彭成寒《JVM G1 源码剖析和调优》

周志明《深刻了解 Java 虚拟机第三版》

美团:Java Hotspot G1 GC 的一些关键技术

退出移动版