当前位置:   article > 正文

深入理解JVM原理-G1收集器_jvm原理有一定了解

jvm原理有一定了解

目录

1、G1背景

2、G1内存模型

2.1、分区Region

2.2、分区Region的RSet

2.3、分区Region的Card卡片

2.2、分区Region的Collect Set(CSet)

3、G1垃圾收集流程

3.1、对象分配策略

3.2、Young GC

3.3、Mixed GC

3.4、Full GC

4、三色标记算法

5、G1 收集器的缺点


1、G1背景

为了取代 CMS 收集器,CMS有以下缺点:

  • CMS收集器对CPU资源非常敏感,会占用CPU资源而导致引用程序变慢;
  • CMS收集器无法处理浮动碎片垃圾,不能像其他收集器那样等到老年代几乎完全被填满了再进行收集;

G1优点:

  • 基于标记-整理算法,不产生碎片化问题;
  • 可以控制停顿时间,提升吞吐量,JDK1.8开始默认G1

G1是标记-清除还是标记-整理算法:

  • G1采用了标记-整理和标记-清除两种方式的结合;
  • 标记-清除发生在并发标记阶段,而标记-整理主要发生在混合收集阶段

2、G1内存模型

2.1、分区Region

     G1 收集器不采用传统的新生代和老年代物理隔离方式收集,采用的是逻辑上划分新生代和老年代。将整个堆内存划分为2048个大小相等的独立内存块Region,大小是2的N次方大概每一块在 1M - 32M 之间,使用不同的Region来表示新生代和老年代,再要求相同类型的 Region 在物理内存上相邻所以是逻辑上划分。每个 Region 分区只能是一种角色,Eden区、S区、老年代O区、H巨型对象区。

     什么是H巨型对象区:大小超过一个Region容量的50%以上的对象存放的区域,为了解决如果它是一个短期存活的巨型对象,放入老年代就会对垃圾收集器造成负面影响,触发老年代频繁GC,所以引入H区概念。如果一个H区装不下巨型对象,G1会寻找连续的H分区来存储,如果寻找不到连续的H区,就启动 Full GC 全局回收。

2.2、分区Region的RSet

RSet是一个反向指针( HashTable 的集合),记录了其它 Region 对当前 Region 的引用情况。回收某个Region时,不需要执行全堆扫描(串行和并行收集器就需要),只需扫描它的 RSet 就可以找到外部引用,来确定引用本Region分区内的对象是否存活。本Region的引用不用记录、新生代的引用也不用记录(因为GC会全部扫描新生代),所以只需要记录新生代和老年代之间的引用。

      哈希表(HashTable )是实现 RSet 的一种常见方式。一个Region可能有多个线程在并发修改,因此也可能会并发修改 RSet。为避免冲突,G1垃圾回收器进一步把 RSet 划分成了多个 HashTable,每个线程都在各自的 HashTable 里修改,从逻辑上来说,RSet 就是这些 HashTable 的集合。

    RSet 的写屏障:每次将一个老年代对象的引用修改为指向年轻代对象,都会被写屏障捕获并记录下来,因此在年轻代回收的时候,就可以避免扫描整个老年代来查找根

2.3、分区Region的Card卡片

一个 Card Table 将一个 Region 在逻辑上划分为若干个固定大小(介于128到512字节之间)的连续区域,每个区域称之为卡片 Card,因此 Card 是堆内存中的最小可用粒度,分配的对象会占用物理上连续的若干个卡片。

     作用:如果一个线程修改了Region内部的引用,就必须要去通知RSet,更改其中的记录,引用的对象很多,赋值器需要对每个引用做处理,开销很大,引入卡片可解决。查找引用是可以通过卡片查找,G1对内存的使用以分区(Region)为单位,而对对象的分配则以卡片(Card)为单位。

2.2、分区Region的Collect Set(CSet

CSet是G1垃待回收的Region集合,用于追踪存活对象,找到所有存活对象并将他们复制到空闲区域中。CSet 所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中。

3、G1垃圾收集流程

G1提供2种GC模式,分别是Young GC和Mixed GC,Full GC是大家都有的

3.1、对象分配策略

一个Region 分为2个部分,已分配和未分配,界限叫做top,所以分配对象就是增加top的值的过程

(1)TLab中分配(线程本地分配缓冲区,ThreadLocal+CAS实现)

如果对象在共享空间中分配就要用ThreadLocal同步机制解决并发冲突问题,对象分配时在这个buff分配线程之间不用进行同步。但是线程消耗完自己buff后依然要申请新的buff也会带来并发问题,这里用CAS解决。对象过大会申请新的buff原来的有空余会浪费掉,带来碎片化问题。

(2)Eden区分配

TLab无法分配的对象才在Eden区分配,如果Eden也无法分配只能在老年代分配了

(3)H区分配

巨型对象在这里分配,无法享受Tlab带来的优化,要避免生成巨型对象。

3.2、Young GC

(1)标记阶段:根扫描

根是只statis指向的对象、变量等,根引用+RSet记录的外部引用作为扫描存活对象的入口

(2)清理阶段:对Eden区和S区垃圾回收,年轻代中没有RSet(记录了老年代到年轻代的引用)引用的会被回收

(3)对象(内存)拷贝

清理阶段完成后,GC将存活对象从Eden区和From S拷贝To S区,并清空Eden区和From S区,同时采用复制算法,GC将To S区和From S区角色互换。

3.3、Mixed GC

年轻代不断进行垃圾回收活动后,为了避免老年代的空间被耗尽(会往老年代送),老年代占用空间达到默认45%时会触发一次混合垃圾回收Mixed GC,对新生代和老年代一起回收。

(需要分配老年代的对象时,但发现没有足够的空间,这个时候就会触发一次 Full GC

Mixed GC分2步骤:并发标记、拷贝存活对象。

(1)全局并发标记

  • 初始标记:标记根节点以及直接可达的对象;
  • 根区域扫描:描初始标记的存活区中( s区)可直达的老年代区域的对象,(因为RSet只记录只被年轻代引用的老年代,在一次Young GC中这些年轻代会被复制到S区);
  • 并发标记:采用三色标记算法, GC Roots 对堆中的对象进行可达性分析,找出存活的对象标记。
  • 重新标记:标记并发标记遗留的对象

(2)拷贝存活对象

3.4、Full GC

当 G1 无法在堆空间中申请新的分区时,G1便会触发担保机制,执行一次STW式的、单线程的 Full GC,Full GC会对整堆做标记清除和压缩,最后将只包含纯粹的存活对象.

G1在以下场景中会触发 Full GC:

  • 从年轻代分区拷贝存活对象时,无法找到可用的空闲分区;
  • 老年代分区转移存活对象时,无法找到可用的空闲分区;
  • 分配巨型对象时在老年代无法找到足够的连续分区;

4、三色标记算法

属于并发收集阶段

  • 黑色:根对象,或者该对象与它的子对象都被扫描了
  • 灰色:对象本身被扫描,但还没扫描完该对象中的子对象
  • 白色:未被扫描对象,扫描完成所有对象之后,最终为白色的为不可达对象,即垃圾对象

5、G1 收集器的缺点

(1)如果停顿时间过短的话,可能导致每次选出的回收集只占堆内存很小一部分,收集器收集的速度逐渐跟不上分配器的分配速度,进而导致垃圾慢慢堆积,最终造成堆空间占满,引发Full GC 反而降低性能。

(2)G1 内存占用、执行负载都要比CMS要高

(3)小内存的情况下使用CMS收集器,大内存的情况下可以使用G1收集器(G1收集器6GB以上)
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/352885
推荐阅读
相关标签
  

闽ICP备14008679号