G1垃圾网络器实现原理

手机游戏开发者 2024-9-29 16:37:00 46 0 来自 中国
1 与垃圾网络器有关的算法

在分析G1前先简单回顾一下与垃圾网络器相关的算法。通常所谓的垃圾网络器更多地是指跟踪垃圾网络器(Tracing Garbage Collection),而不是引用计数(Reference Counting )垃圾网络器。跟踪垃圾网络器接纳可达性分析方法确定哪些对象要被接纳,通常会选取一些对象作为GC Roots,假如对象能直接或间接地被GC Roots中的对象引用,则认为该对象可达(存活对象)不能被接纳,否则该对象不可达(垃圾对象)要被接纳。
1.1 三色标志算法

在确定内存中哪些对象是垃圾对象时,可以接纳最简单的标志算法,即给内存中每个对象一个专门的标志位,被标志则认为是存活对象,否则是垃圾对象,然从GC Roots的对象集合开始递归遍历对象图,假如对象图中的对象能被GC Roots中的对象直接或简接引用则举行标志。理论上该算法可以确定内存中哪些对象是存活的,哪些对象是垃圾,但整个过程应用步伐必须暂停,并且要处理全部的内存地区。
为相识决上面的标题,Dijkstra等人在On-the-Fly Garbage Collection: An Exercise in Cooperation 一文中提出了三色标志(Tri-color Marking)算法。像Go、JavaScript 、Java等语言在内存接纳上都接纳了三色标志算法的变种。
三色标志算法会创建白色、灰色、玄色三个集合,三个集合内分别只存储白色对象、灰色对象、玄色对象。白色对象,代表尚未开始标志的对象或已完成标志并确认为垃圾的对象;灰色集合,代表还在标志中的对象,即遍历对象图时已遍历到本身,但还未完成本身引用 对象的遍历;玄色对象,代表已完成标志并确认为存活的对象(正常环境下,对象标志的颜色厘革只能白色酿成灰色,灰色酿成玄色)。起初玄色集合通常为空,灰色集合内为GC Roots直接引用的对象,其他对象均在白色集合内。一个对象任一时候只能在白色、灰色、玄色三个集合中的某一个。通常三色标志算法的处理流程如下:
1、起初除GC Roots 外的其他对象全白色集合,将GC Roots直接引用的对象从白色集合内移到灰色集合。
2、从灰色集合取出一个灰色对象,依次处理该对象引用的对象。若其未引用任何对象,则直接将其移入玄色集合中;若其引用的对象在白色集合中则将其移入灰色集合,否则直接不处理,当该灰色对象引用的对象全处理完后,再将其移入玄色集合中。
3、重复第2步的流程直到灰色集合为空。
4、上面的步调处理完后,GC Roots与玄色集合内的对象为存活对象,而白色集合内的对象为垃圾对象,末了要做的就是将白色集合内的垃圾对象整理。
下图展示了除GC Roots 别的有8个对象时,三色标志算法的处理流程。

  • 起初除了GC Roots内的对象外,其他对象全在右则的白色集合中。
1.png

  • 将GC Roots直接引用的对象从白色集合内移到灰色集合后,此时A对象与F对象已从白色集移到灰色集合。
2.png

  • 处理完灰色集合中的A对象引用的B对象后,此时B对象已从白色集移到灰色集合。


  • 处理完灰色集合中的A对象引用的C对象与D对象后。此时A对象已从灰色集合移到玄色集合,C对象与D对象已从白色集移到灰色集合。


  • 处理灰色集合中剩余的B对象、C对象、D对象与F对象后,B对象、C对象、D对象与F对象象已从灰色集移到玄色集合。
5.png

  • 履历过上面的处理后灰色集合已为空,三色标志法标志阶段竣事到达整理阶段,白色集合中的E对象、G对象与H对象被整理,末告终果如下图。
1.2 三色标志算法的不敷

假如应用步伐线程与三色标志算法的GC线程一起运行,则大概出现对象错标与漏标。所谓的对象错标是指原为是垃圾的对象被标志为玄色认为是存活的,这种环境的出现并不会引起应用步伐的错误,只是会将垃圾网络的时间延误到下一次垃圾接纳。而对象漏标,则是本来要标志为玄色的对象,被遗漏了,没有被标志,最终导致该对象在白色集合中被垃圾接纳集给接纳掉;这种环境的一旦发生应用步伐将出现未知的异常,这个异常大概是无关紧急的也大概是致命的。
以上面的例子来看看漏标是怎么发生的。
7.png 假设GC线程预备下一步标志工作前,对象的标志状态如上图。此时GC线程下一步将处理灰色集合中的F对象,由于F对象未引用任何对象其将直接移动到玄色集合中,团体个灰色集合为空标志竣事。但是假如在GC线程还未完成F对象从灰色集合转移到玄色集合的利用时,应用线程恰好增长了F对象对G对象的引用呢?
8.png 由于F对象已竣事标志工作(现实GC线程已认为F对象是玄色的),F对象最终还是会从灰色集合乐成地转移到玄色集合。而GC线程将无法感知应用步伐新增长的F对象到G对象的引用,最终导致G对象的漏标。现实上产生漏标肯定会满意下面两种环境的一种。
1、GC线程标志的过程中,应用线程增长玄色对象到白色对象的引用
2、GC线程标志的过程中,应用线程删除了灰色对象到白色对象的引用
上面的漏标示例现实是第一种环境,论文Uniprocessor Garbage Collection Techniques 的 3.2.1 Incremental approache末节将处理漏标时关注的点差异将GC分为 Snapshot-at-beginning collectors 与 Incremental update collectors。Snapshot-at-beginning collectors 关注于处理第一种环境,而Incremental update collectors关注于处理第二种环境,G1属于Snapshot-at-beginning collectors,而CMS属于Incremental update collectors。G1并发标志过程关注处理应用线程增长玄色对象到白色对象的引用,即当玄色对象新引用了白色对象时,便将这个玄色对象重新设置为灰(技能实现上接纳pre-write barrier) ;而CMS发标志过程关注处理线程删除了灰色对象到白色对象的引用,即当灰色对象删除了白色对象的引用时,便将这个白色对象直接置灰(技能实现上接纳post-write barrier)。
那详细接纳何种技能本领处理上面的两种环境呢?着实也很简单,就是想办法让GC线程感知对象引用的厘革,即所谓的写屏蔽(write barrier)。这里的所说的写屏蔽并不是硬件层面的写屏蔽,而是软件层的写屏蔽,着实质可明白为在引用赋值这个写利用前加一个切面,根据切点参加机遇差异又可分为 pre-write barrier 与post-write barrier,下面是G1中接纳的写屏蔽的伪代码实现(泉源于[HotSpot VM] 讨教G1算法的原理 )。
void oop_field_store(oop* field, oop new_value) {  pre_write_barrier(field);             // pre-write barrier: for maintaining SATB invariant  *field = new_value;                   // the actual store  post_write_barrier(field, new_value); // post-write barrier: for tracking cross-region reference}G1中利用pre-write barrier来包管并发标志过程中要处理的SATB(snapshot-at-the-beginning)的完备性(G1 SATB详细怎样的实现背面会详细分析),即GC线程在跟踪标志开始阶段生成的对象图快照时,应用线程对该对象图快照的修改能通过pre-write barrier感知。另一方面G1接纳post-write barrier来维护并发标志过程中应用线程新产生的必要跟踪的跨区间引用(背面分析G1的RSet时会再增补阐明)。
1.3 对象的扫除实现方式

当对象标志竣事后,便可以扫除对象。而在详细实现时可以接纳三种方式标志扫除、标志复制、标志压缩算法。标志扫除最为简单与高效,其直接将那些垃圾对象扫除,但这也带来了内存碎片的标题,同时对象分配时也不得不接纳空闲空间列表算法而不能接纳高效的指针碰撞算法。标志复制算法通常要额外占用50%的空间,着实现是不停用一半内存存储对象,而另一半内存置空,当接纳垃圾时,将已利用空间中仍存活的对象直接复制到置空的那段内存中,然后直接置空之前利用的那半内存。标志压缩算法,分身标志扫除与标志复制算法的长处,在接纳垃圾后会对存活对象举行相应的移动,只管将碎片化的内存空间举行压缩。
2 分代垃圾网络器

在分析G1垃圾网络器之前有须要先简单回顾一下HotSpot VM中的其他垃圾网络器。在G1出现之前HotSpot VM中的其他垃圾网络器都是基于新生代与年老代举行垃圾接纳的,这些垃圾接纳器集统称为分代垃圾。而G1则是分因素代与分区的垃圾网络器。
2.1 分代垃圾网络器垃圾网络过程

分代垃圾网络器将Heap分别为新生代(Young Generation)与年老代 (Old Generation),在JDK1.8 之前另有永世代(Permanent Generation)的概念。新生代又被进一步分别为Eden、From Space 、To Space,此中 From Space 与 To Space 巨细相称又称作Survivor Spaces。
Heap被分别为新生代与年老代是基于弱分代假设的,在java应用步伐与其他应用步伐中都可以观测到弱分代假设的征象。
1、大多数分配的对象不会被恒久引用(被认为是存活的)即他们很年轻就死去。
2、老对象很少持有来自新对象的引用。
新生代垃圾接纳相对频仍,且利用的算法高效快速,由于年轻代空间通常很小并且大概包罗许多不再被引用的对象。而年老代垃圾接纳频率则相对较低,但由于年老代占用内存相对更多,通常老代垃圾接纳将更加耗时。新生代与年老代分别存储差异年龄的对象,通常刚分配内存的对象被存储在新生代,每颠末一次垃圾接纳假如对象还存活其年龄将加1,当颠末多轮垃圾接纳后假如对象的年龄高出了MaxTenuringThreshold值,该对象将提升到年老代。
由于新生代垃圾接纳相对更加频仍,新生代垃圾接纳更加关注垃圾接纳的时效性,通常会接纳复制算法或标志扫除算法处理垃圾接纳。年老代占用内存相对更大,而垃圾接纳频仍较低,年老代垃圾接纳更加关注垃圾接纳的空间性,即垃圾接纳后可否开释更多连续的内存,通常会接纳压缩算法处理垃圾接纳。
如今来简单看看对象如安在Eden、Survivor与Old Generation之间举行分配与转移的。

  • 任何新对象都被分配到新生代的Eden空间,当Eden地区无法容纳新对象时,会触发一次Young GC。 最开始时两个Survivor空间都是空(下图是已颠末多少次GC的环境)。
10.png

  • Young GC 过程中Eden空间仍被引用的对象(存活对象)会被复制到第一个Survivor空间(S0 Survivor Space)。 而Eden 空间未被引用的对象将被直接删除。履历过一次Young GC后仍存活的对象,其年龄都会增长1,下图S0 Survivor Space中的对象都只履历一次Young GC,全被标志为1。


  • 下一次Young GC 中仍被引用的对象(存活对象)会被复制到之前是空的Survivor空间(To survivor space ,现实是之前的S1 survivor space),Eden 空间未被引用的对象将被直接删除。 之前的S0 suvivor space如今称为Form survivor space,此中依靠被引用的对象,被复现到了之前是空的Survivor空间(To survivor space ),Form survivor space 未被引用的对象将被直接删除。仍被引用的对象从Form survivor space复制到To survivor space后,其对象年龄将加1,表明该对象又履历了一次Young GC。
12.png

  • 再下一次Young GC 中,会重复上面相同的过程。 但这时Survivor space 脚色将举行互换,即From survivor space 酿成 To survivor space,To survivor space 酿成 From survivor space。这个互换的目标现实就是为了将已利用的Survivor space中仍存活的对象复制到被清空的Survivor space中。
13.png

  • 当履历许多次Young GC后新生代中仍存活的对象将会提升(Promotion)到老年代。下图展示了当MaxTenuringThreshold参数为8 时,仍存活的对象重新生代的From survivor space提升到老年代。
14.png

  • 随着Young GC 的不停发生,新生代中仍存活的对象将不停地提升到年老代。最终老年代将没有更多的空间容纳新提升的对象,此时引发Major GC。
对象分配与提升时何时会触发GC的详细流程图可以参考下图(参考了《码出高效:Java开发手册》第四章走进JVM中的图):
16.png 上图中没有描画出 Thread Local Allocation Buffer (TLAB)与 Promotion Local Allocation Buffer (PLAB)的细节。别的上图中的Full GC大概让各人引起歧义,由于和Major GC太轻易肴杂了。现实JVM规范与垃圾收回相关的文献并没有给Full GC 与 Major GC作界说。一样寻常Full GC认为是对新生代与老年代都举行垃圾接纳,而Major GC则是专门针对年老代垃圾举行接纳。那标题来了由Young GC 引发了老年代的垃圾接纳,是叫Full GC好呢,还是Major GC好呢?个人认为大概Full GC更符合,这个各人可以不消过多纠结这个。实现纠结可以看看这两篇文章Minor GC vs Major GC vs Full GC 与 Major GC和Full GC的区别是什么?触发条件呢?。
上面只简单的描述了分代垃圾网络器垃圾网络的过程,现实垃圾网络器不但负责了内存的接纳工作,同样负责了对象的分配工作。更多的入门内容可以参考Memory Management in the Java HotSpot™ Virtual Machine 、Plumbr Handbook Java Garbage Collection。假如想再进一步相识垃圾接纳相关的东西,还可以看看 《垃圾接纳算法手册 自动内存管理的艺术》。
2.2 串行垃圾网络器

串行垃圾网络器(Serial GC)在举行垃圾接纳时只有单个GC线程在举行垃圾接纳。通常实现串行垃圾接纳器更加简单,串行垃圾接纳器内部不消维护复杂的数据结构,内存开销也更加小。但由于在STW(Stop The World)时只有单个GC线程在举行垃圾接纳工作,垃圾接纳的时间通常都会比力长,并且与应用步伐占用的内存呈线性增长。该垃圾接纳器比力得当Client端与嵌入设备等占用内存较小的场景。
上图灰色箭头为应用线程,而玄色箭头为GC线程,应用线程在工作时通常都是多线程,而到过安全点后应用线程克制工作也叫SWT(Stop The World),串行垃圾接纳器将开始一个GC线程完成垃圾接纳工作。根据接纳分代的差异串行垃圾接纳器通常又分为Serial New 与 Serial Old,他们分别负责接纳新生代(Young Generation)与年老代(Old Generation)。Serial New接纳复制算法完成垃圾整理工作,Serial Old接纳压缩算法完成垃圾整理工作。
2.3 并行垃圾网络器

很显然在多核CPU架构下面垃圾接纳时,串行垃圾接纳器不能利用多核CPU的上风。因此出行了并行垃圾网络器(Parallel GC),其与串行垃圾接纳器最大的差异在于STW时,举行垃圾接纳的线程由单个酿成了多个。相对于串行垃圾接纳器而言,由于垃圾接纳的工作被分配给了多个线程,每次举行GC时团体时间将大大降落。并行垃圾接纳器工作时,新生代与年老代都会接纳线程并行处理垃圾接纳工作。与串行垃圾接纳器一样,并行垃圾接纳器,根据接纳分代的差异通常又分为ParNew 与 Parallel Old,他们分别负责接纳新生代(Young Generation)与年老代(Old Generation)。同样新生代垃圾接纳接纳复制算法完成垃圾整理工作,年老代接纳压缩算法完成垃圾整理工作。
上图灰色箭头为应用线程,而玄色箭头为GC线程,并行垃圾接纳器在STW时举行垃圾接纳的线程相对于串行垃圾接纳器而言酿成了多个线程,并且这些线程同时举行垃圾接纳工作。
2.4 并发标志扫除垃圾网络器

并发标志扫除垃圾网络器 (Concurrent Mark Sweep,CMS )是Hotspot VM上真正意义上的并发垃圾接纳器。所谓并发(Concurrent)是指GC线程与应用线程一起工作,GC线程工作时不消STW,应用线程也在工作,而通常说的并行(Parallel)是指多个GC线程同时工作,整理垃圾。许多文献中将应用线程叫作Mutator Thread。
CMS 紧张负责接纳年老代垃圾,利用CMS时新生代垃圾网络工作通常由Serial New 或 ParNew 完成,默认新生代垃圾接纳器为ParNew。CMS接纳年老代垃圾时,将团体垃圾接纳的过程拆分为多个阶段,并且大部分阶段与应用线程都是并发不会发生STW。CMS团体垃圾接纳过程可分为初始化标志( Initial-mark)、并发标志(Concurrent Marking)、并发预扫除(Concurrent Pre-cleaning)、重新标志(Remark)、并发扫除(Concurrent Sweeping),初始化标志与重新标志都会发生STW,但通常时间都比力短。CMS早其版本中初始化标志与重新标志都是由单线程完成的,后期版本可以通过 -XX:+CMSParallelInitialMark 与 -XX:CMSParallelRemarkEnabled 分别将初始化标志与重新标志阶段指定为多线程。在CMS对年老代举行并发接纳时许多大概新生代发生了Young GC,此时年老代垃圾接纳将立刻停止,直到Young GC竣事后又重新规复。

上图灰色箭头为应用线程,而玄色箭头为GC线程,CMS在Initial-mark阶段开启多个GC线程对GC Root举行标志,该阶段通常时间会比力短。CMS在并发标志与并发预扫除阶段同会开启多线程工作,该阶段GC线程与应用线程并发工作。上图中Concurrent Making Pre-cleaning 阶段中长的玄色箭头代表处理Concurrent Making工作的GC线程,短的玄色箭头代表处理Pre-cleaning工作的线程。CMS在重新标志同样开启多个GC线程并且与Initial-mark阶段一样会SWT。CMS在并发扫除阶段GC线程与应用线程并发工作。
CMS调优的一个关键标题是怎样找出符合的时间让CMS开始并发工作,以便在应用步伐耗尽可用的堆空间之前CMS完成全部的并发工作。通常会某次Young GC后开始CMS的并发工作,由于Young GC过后 CMS Initail-mark 要标志的对象通常会更少。CMS别的的一个标题是年老代内存碎片标题,由于CMS在接纳年老代时接纳了标志扫除算法,标志扫除算法相对于压缩算法而言实行服从更高,但由于整理垃圾时没有对内存的压缩整理,其不可制止地会出现内存碎片标题。下面二种环境会由于内存碎片标题最终导致concurrent mode failure。
1、Young GC 时,Eden地区存活的对象过大Survivor地区无法存放导致promotion failed,此时对象只能放入年老代,但由于内存碎片标题年老代同样放不下该对象,末了将发生concurrent mode failure,这时会引发Full GC,Full GC会接纳整个Heap 空间导致STW时长骤增。
2、Young GC 时,Survivor 地区存活对象年龄高出了MaxTenuringThreshold,提升到年老代,但由于内存碎片标题年老代放不下该对象,将发生concurrent mode failure,这时会引发Full GC。
更多关于CMS调优方面的实践可以参考这两篇文章 Java中9种常见的CMS GC标题分析与办理 与 Understanding GC pauses in JVM, HotSpot's CMS collector
下面是一张关于HotSpot VM 中垃圾接纳器怎样组合分别处理年轻代与年老代的经典图。上面部分的Serial New、ParNew、Parallel Scavenge 都是专门用于处理新生代垃圾网络器,下面部分的CMS、Serial Old、Parallel Old是专门用于处理年老代的垃圾网络器,而处于中心的G1即能处理新生代也能处理年老代。图中的玄色实线代表哪些新生代垃圾网络器能与哪些年老代垃圾网络器组合工作。CMS与Serial Old之间的玄色虚线代表CMS发生concurrent mode failure时fail safe成Full GC接纳Serial Old接纳年老代垃圾。
上面提到的Serial GC(Serial New 与 Serial Old)、Parallel GC(ParNew、Parallel Scavenge、Parallel Old)、CMS,由于新生代与年老代其内存结构是连续的(虚似内存是连续的)这些垃圾网络器在接纳垃圾时要么只能处理详细某一个分区要么只能处理整个Heap。这肯定会导致垃圾接纳的STW时间或多或少与应用步伐占用内存线性正相关,即应用步伐占用的内存越大在实行垃圾接纳时STW时间将越久。前面的垃圾网络器都是分代的垃圾网络器,G1开启了分区垃圾网络器的先河(固然G1在逻辑上也有新生代与年老代的概念)。G1利用分治的头脑将团体Heap分别为一块块巨细相称的Region,在内存管理时可以针对这些Region举行管理,而不是笼统地对某个Generation举行管理。由于Region的巨细通常远小于Generation,垃圾接纳时处理多个Region服从通常高于处理某个Generation。
3 G1垃圾网络器概述

G1(Garbage First)垃圾网络器是续CMS网络器后的另一款跨期间的垃圾网络器,其开启了分区垃圾网络器的先河。G1通逾期间推测模子尽大概地满意用户对暂停时间的要求(用户可以通过-XX:MaxGCPauseMillis=XXX,来指定垃圾收回时最大的暂停时间),G1 利用压缩算法优化接纳垃圾更多的分区,以是他被称作垃圾优先(Garbage First)垃圾网络器。
3.1 G1 垃圾收会集的内存结构

G1与上面先容的传统分代垃圾网络器一样同样存在Eden Generation、Survivor Generation、Old Generation的概念,但与他们最大的区别在于这些Generation的关系是逻辑上的关系,其各Generation内存结构不会存在连续性。G1 将Heap分别为一个个Region,每个Region的巨细为2的N次方,其值在1M到32M之间。每一个Region属于某个Generation,于是有了Eden Region、Survivor Region、Old Region/Tenured Region的概念(不像传统分代垃圾网络器,G1中没有From Survivor 与 To Survivor的概念, 由于G1不管是Young GC、Mix GC、Full GC 对象都是从一个Region转移到别的一个Region或是直接扫除)。除此之外G1另有一个专门用于存放大对象的Region(默认对象占用内存高出Region巨细二分之一的对象),称为Humongous Region,Humongous Region 大概由多个Region构成,但一个Region最多存放一个大对象,当多个Region用于存放一个特别大的对象这些Region内在结构上是连续的。当颠末多次Young GC、Mix GC、Full GC与对象分配后(G1中Young GC、Mix GC、Full GC 相关的东西背面会涉及),Eden Region、Survivor Region、Old Region、Humongous Region之间的脚色会变化,即原来存有详细某种Generation对象的Region被清空后可以用来存放Eden对象、Survivor对象、Old 对象或是Humongous对象中的某一种。

21.png 这种将内存分为一个个Region的内存结构更加有利于内存的接纳,垃圾接纳集可以接纳分治的头脑去管理一小块的内存(处理内存的分配与接纳),制止了之前版本垃圾接纳集在处理Old Generation时只能处理整个Old Generation困局(整个Old Generation一起处理通常非常耗时的,而且这个过程中制止不了STW)。
3.2 G1 垃圾网络的周期

从全局视角来看,G1网络器接纳垃圾的过程是在Young-only 阶段与Space Reclamation阶段之间举行瓜代的,下图泉源于Oracle官网HotSpot Virtual Machine Garbage Collection Tuning Guide 一文中。


  • Young-only 阶段
    Young-only阶段现实包罗了多次Young GC 与整个并发标志过程。其从一些普通的Young GC(上图中小的蓝色点代表普通的Young GC)开始,并将满意条件的对象提升到老年代。当年老代占用内存高出阈值时,会触发并发标志阶段,该阈值由参数-XX:InitiatingHeapOccupancyPercent=65%,指定默认值为65%。与此同时G1会开启并发的Young GC(上图中大的蓝色大代表并发的Young GC) ,而不是普通的Young GC。整个并发标志阶段是与普通的Young GC瓜代的。并发标志阶段又可细分为初始化标志(Initial Marking)、重新标志(Remark)与整理(Cleanup)阶段。初始化标志阶段现实是在并发的Young GC中完成的(文献中通常用piggybacking一词表述)。当初始化标志完成后大概会发生多少的普通Yong GC,才进入Remark阶段(上图中靠上方的黄色小点)。接着并发标志大概被Young GC打断,Young GC竣事后再进入Cleanup阶段(上图中靠下方的黄色小点)。
  • Space Reclamation 阶段
    当Cleanup竣事后,G1会进入Space Reclamation 阶段,该阶段由多少次的MixGC构成。每次MixGC都会从之前并发标志阶段标志的对象中选择一部分举行整理,MixGC过程中同时陪伴着部分的Young GC(上图中赤色的小点代表一次MixGC)。当G1发现扫除对象所获取的空间不敷多时将克制MixGC,与此同时Space Reclamation 阶段竣事。
当Space Reclamation 阶段竣事后,G1网络周期又重一个Young-only阶段重新开始。Young-only中的普通Young GC的触发条件与前分的分代垃圾网络器Young GC触发条件同等,只不外G1是针对Region处理的,即G1会根据Eden Region中是否有Region能够容纳新对象来决定是否要开启Young GC。作为兜底战略,当G1垃圾接纳过程开释的内存不敷于满意应用步伐中新对象对内存要求时,G1会接纳Full GC处理全部Region。
3.3 影象集(RSet)

前面已相识到Young GC时只会处理新生代对应的Region即 Eden Region与Survivor Region,这有利于低落每次Young GC的时间。但假如 Eden Region与Survivor Region持有老年代的引用呢,岂非在Young GC时,要把Heap中全部的Region都遍历一次才气确定Eden Region与Survivor Region有哪些对象才是垃圾吗?这种方式显然是不可取的,这样一来就会拉长Young GC的时间。
有种有用地方法是新生代的每一个Region都维护一个集合记录一下老年代指进来的(point-in)的跨代引用,这样在Young GC时只要看一下这个point-in的集合就行,这个集合便是所谓的影象集(Remember Set,RSet)。那年老代内里必要这个RSet吗?前面提到每次Mix GC时会接纳部分年老代的Region,假如没有这个影象集的话和Young GC一样同样制止不了要扫描整个年老代的Region,以是年老代的Region也要维护一个point-in的集合,不外个集合记录是Old Region point-in 过来的集合,至于Young Region point-in 过来的则可以不消管。
那RSet详细实现上又是怎么样的呢?在这之前必须先知道卡表(CardTable),在G1之前CMS中也有CardTable。CardTable本质上是一种point-out数据结构,表现某一地区本身有指向别的地区的引用。在G1中CardTable由byte数组构成,数组的每个元素称之为卡片/卡页(CardPage)。CardTale会映射到整个堆的空间,每个CardPage会对应堆中的512B空间。如下图所示,在一个巨细为8GB的堆中,那么CardTable的长度为16777215 (8GB / 512B);假设-XX:G1HeapRegionSize参数为2MB,即每个Region 巨细为2 MB,则每个Region都会对应4096个CardPage。CardTable将占用16MB额外内存空间。
查找一个对象地点的CardPage只必要应用如下公式便可得出。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-23 16:18, Processed in 0.167563 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表