能够参考本文末尾财富章节里引用的杂质回收手册一书,能够参照本文末尾能源章节里引用的污物回收手册一书

作者: Maoni Stephens (@maoni0) – 2015

作者: Maoni Stephens
(@maoni0) – 2015

附:
关于垃圾回收的音讯,可以参见本文末尾财富章节里引用的废料回收手册一书。

附:
关于垃圾回收的音信,能够参考本文末尾能源章节里引用的排放物回收手册一书。

零件架构

GC蕴涵的多个零件分别是内部存款和储蓄器分配器和废品收集器。内存分配器负责获取更加多的内部存款和储蓄器并在适龄的时候接触垃圾收集。垃圾收集器回收程序中不再行使的对象的内部存款和储蓄器。

有各类办法调用垃圾回收器,例如人工资调整用GC.Collect也许当终结线程在接收到代表低内部存款和储蓄器的异步公告时(调用)。

组件架构

GC包蕴的多个零部件分别是内存分配器和垃圾收集器。内部存款和储蓄器分配器负责获取越多的内部存款和储蓄器并在杰出的时候接触垃圾收集。垃圾收集器回收程序中不再使用的对象的内部存款和储蓄器。

有各个艺术调用垃圾回收器,例如人工调用GC.Collect恐怕当终结线程在接到到代表低内部存款和储蓄器的异步通告时(调用)。

内部存款和储蓄器分配器的规划

内存分配器由履行引擎(EE)的内部存款和储蓄器分配帮衬函数调用,并附着下列音信:

  • 请求的分寸
  • 线程分配上下文
  • 3个证实该对象是还是不是可告竣的标识。

GC不会有别对待不一样的对象。请通超过实际施引擎来获得对象的分寸。

依照对象的高低,GC将其分为两类:小目的(< 85,000字节)和大目的(>=
85,000字节)。原则上,大小对象都足以等效处理,不过压缩大目的花费越发昂贵所以GC才那样区分。

GC向内部存款和储蓄器分配器释放内存是经过内部存款和储蓄器分配上下文实现的。内部存款和储蓄器上下文的轻重缓急有分红额度定义:

  • 内部存款和储蓄器分配上下文(Allocation contexts)是线程专用的堆区(heap
    segment)上小一些的区域。在单处理器(即三个逻辑处理器)机器上,使用单上下文,也正是第0代内部存储器分配器上下文。
  • 内部存款和储蓄器分配定额(Allocation
    quantum)
    是分配器在三个内存分配上下文中执行对象分配时需求越来越多内部存款和储蓄器时的分红定额。这么些定额常常是8k,而托管对象的平均大小大致是叁17个字节,那样在七个分红额度里能够满意众多目的的分配请求。

大目的不应用分配上下文和定额。2个大目的自小编就比那么些小内部存款和储蓄器区域(8k的定额)大了。而且,这个区域的亮点(下文研商)直适用于小指标。大目的就平素在堆区上分红了。

分配器的布置性目的如下:

  • 在适合的时候触发GC: 分配器在超越分配预算(由收集器设置的叁个阈值)时,只怕分配器无法在堆区上分红时触发GC。后文子禽详细介绍分配预算和托管堆区。
  • 保存对象的本地性: 在同多个堆区上分红的对象,保存它们的虚拟内部存款和储蓄器地址也是挨着的。
  • 提升缓存的频率: 分配器以 分配定额 为单位分配内存,而按不是3个个对象分配。其将那个内部存款和储蓄器置零来便CPU的缓存提前做准备,因为随着立刻就有对象在那块内部存款和储蓄器中创立。分配定额平时是8k。
  • 拉长锁的频率: 内部存款和储蓄器分配上下文的线程关联性和定额保障有且唯有贰个线程写入钦命的定额分配的内部存款和储蓄器。结果就是只要当前的内部存款和储蓄器分配上下文没有用光的话,对象分配是不须求加锁的。
  • 内部存储器完整性: 对于新创设的靶子,GC总是将内部存款和储蓄器置零,以幸免对象引用了随机的内存地点。
  • 保持堆的可遍历性: 分配器保证定额的剩余内部存款和储蓄器是1个空暇对象。例如,若是定额里只剩余贰拾4个字节,而下三个要分配的目的大小是40字节,分配器为那二二十一个字节创造三个有空对象并提请二个新的分红定额。

内部存款和储蓄器分配器的宏图

内部存款和储蓄器分配器由实践引擎(EE)的内部存款和储蓄器分配帮助函数调用,并附着下列音讯:

  • 呼吁的深浅
  • 线程分配上下文
  • 四个证实该对象是否可完工的标识。

GC不会分别对待不相同的对象。请通超过实际施引擎来获取对象的深浅。

基于对象的轻重缓急,GC将其分为两类:小目的(< 85,000字节)和大指标(>=
85,000字节)。原则上,大小对象都足以一样处理,不过压缩大目的开支尤其昂贵所以GC才这么区分。

GC向内部存款和储蓄器分配器释放内部存款和储蓄器是透过内部存款和储蓄器分配上下文完结的。内部存款和储蓄器上下文的大大小小有分红额度定义:

  • 内部存款和储蓄器分配上下文(Allocation contexts)是线程专用的堆区(heap
    segment)上小一些的区域。在单处理器(即三个逻辑处理器)机器上,使用单上下文,也正是第0代内部存款和储蓄器分配器上下文。
  • 内存分配定额(Allocation
    quantum)
    是分配器在2个内部存款和储蓄器分配上下文中实施对象分配时须要越来越多内存时的分红定额。这一个定额平常是8k,而托管对象的平均大小大概是三十个字节,那样在3个分红额度里可以满足众多指标的分配请求。

大目的不使用分配上下文和定额。三个大目的自作者就比这一个小内部存款和储蓄器区域(8k的定额)大了。而且,那一个区域的长处(下文研讨)直适用于小目的。大指标就径直在堆区上分红了。

分配器的安插指标如下:

  • 在适度的时候触发GC:
    分配器在超越分配预算(由收集器设置的3个阈值)时,只怕分配器无法在堆区上分红时触发GC。后文种详细介绍分配预算和托管堆区。
  • 保留对象的本地性:
    在同贰个堆区上分红的靶子,保存它们的虚拟内部存款和储蓄器地址也是挨着的。
  • 增强缓存的频率: 分配器以 分配定额
    为单位分配内部存储器,而按不是3个个目的分配。其将那个内部存款和储蓄器置零来便CPU的缓存提前做准备,因为随着霎时就有目标在这块内部存款和储蓄器中创造。分配定额经常是8k。
  • 提升锁的频率:
    内存分配上下文的线程关联性和定额保障有且唯有二个线程写入钦定的定额分配的内部存款和储蓄器。结果正是要是当前的内部存款和储蓄器分配上下文没有用光的话,对象分配是不供给加锁的。
  • 内部存款和储蓄器完整性:
    对于新成立的指标,GC总是将内部存款和储蓄器置零,以预防对象引用了随机的内部存款和储蓄器地方。
  • 维持堆的可遍历性:
    分配器保险定额的盈余内部存款和储蓄器是贰个空闲对象。例如,假使定额里只剩下叁11个字节,而下3个要分配的靶子大小是40字节,分配器为那贰十五个字节创建一个悠然对象并提请3个新的分配定额。

内部存款和储蓄器分配 APIs

 Object* GCHeap::Alloc(size_t size, DWORD flags);
 Object* GCHeap::Alloc(alloc_context* acontext, size_t size, DWORD flags);

上边的函数能够用来分配大指标和小指标。也有三个对象能够直接在大指标堆里分配内部存款和储蓄器:

 Object* GCHeap::AllocLHeap(size_t size, DWORD flags);

内部存款和储蓄器分配 APIs

 Object* GCHeap::Alloc(size_t size, DWORD flags);
 Object* GCHeap::Alloc(alloc_context* acontext, size_t size, DWORD flags);

地点的函数能够用来分配大指标和小目的。也有三个对象可以一贯在大目的堆里分配内部存款和储蓄器:

 Object* GCHeap::AllocLHeap(size_t size, DWORD flags);

收集器的统一筹划

收集器的设计

GC的目标

GC将最为便捷利用内部存款和储蓄器和尽量防止编写“托管代码”的程序员的人造干预作为奋斗指标。高效是指:

  • GC应该丰硕频仍产生,以免止托管堆上有恢宏(按比率只怕相对值)已分配的但于事无补的对象(垃圾),导致非需要的运用内存。
  • GC应该尽量不频仍产生,防止占用有用的CPU时间,哪怕在低内部存款和储蓄器导致的反复GC。
  • GC应该有赶快产出。假设GC只回收了一小部分内部存款和储蓄器,那么GC(包罗其选拔的CPU周期)都以荒废的。
  • 老是GC应该尽大概快。很多行事负荷必要低顺延。
  • 托管代码程序员应该不供给领会GC的太多细节而能达到规定的标准飞快的内部存款和储蓄器使用率。
  • GC应该本人调整以满意不相同的内部存款和储蓄器使用形式。

GC的目标

GC将最为便捷使用内部存款和储蓄器和尽量防止编写“托管代码”的程序员的人造干预作为奋斗目的。高效是指:

  • GC应该丰裕频繁发生,以免止托管堆上有恢宏(按比率或然相对值)已分配的但不算的对象(垃圾),导致非要求的运用内部存款和储蓄器。
  • GC应该尽量不频仍产生,防止占用有用的CPU时间,哪怕在低内部存款和储蓄器导致的数次GC。
  • GC应该有高效产出。假使GC只回收了一小部分内部存款和储蓄器,那么GC(包蕴其应用的CPU周期)都以荒废的。
  • 历次GC应该尽量快。很多办事负荷须求低顺延。
  • 托管代码程序员应该不供给领悟GC的太多细节而能落得飞速的内部存款和储蓄器使用率。
  • GC应该自我调整以满意不一致的内部存款和储蓄器使用方式。

托管堆的逻辑方式

CL奥迪Q5GC是一个分代收集器,即对象是逻辑划分成多少个代的。当第 N 代收集完成后,剩下来的幸存对象则被标识为第 N+1 代。那几个历程被称作升级。也有很是情形大家决定降级或许不升级。

小目标堆被分为3代:gen0, gen1和gen2。大目的唯有一代 –
gen3。gen0和gen1被誉为短命代(对象共处的时日十分长)。

对此小指标堆,代的数字代表它的年龄 -
gen0属于最青春的一世。那不是说gen0里具有的对象比gen1或gen第22中学肆意2个指标年轻。后文种提到一些万分动静。收集一代是指收集那时代和拥有比其年轻的代。

规则上海大学指标能够利用跟小对象相同的措施处理,然则压缩大目的的代价很高,才差别对待。出于品质的考虑衡量,大指标唯有一代而且接二连三跟gen2一起收集。gen2和gen3足以十分大,可是收集短命代(gen0和gen1)的资本有限量。

内部存款和储蓄器分配是在最年轻的代产生的 -
对小指标的话总是gen0,而对大目的的话是gen3,因为唯有一代。

托管堆的逻辑情势

CL凯雷德 GC是三个分代收集器,即对象是逻辑划分成多少个代的。当第 N
代收集完成后,剩下来的依存对象则被标识为第 N+1
代。这几个进度被称作升级。也有十分景况大家决定降级或许不升级。

小目标堆被分为3代:gen0, gen1和gen2。大指标只有一代 –
gen3。gen0和gen1被称之为短命代(对象共处的时日十分长)。

对此小指标堆,代的数字代表它的年龄 -
gen0属于最青春的时代。那不是说gen0里有着的靶子比gen1或gen第22中学自由贰个对象年轻。后文少禽提到一些万分动静。收集一代是指收集那时期和拥有比其年轻的代。

原则上大目的能够动用跟小对象相同的章程处理,可是压缩大目的的代价很高,才差别对待。出于品质的勘察,大指标唯有一代而且连连跟gen2一起采访。gen2和gen3足以相当的大,可是收集短命代(gen0和gen1)的资本有限制。

内部存款和储蓄器分配是在最青春的代发生的 -
对小目的的话总是gen0,而对大目标的话是gen3,因为只有时期。

托管堆的大体格局

托管堆是一多元的托管堆区。叁个托管堆区是GC从操作系统那里申请的一个连接的内存区域。堆区被分为大小对象区,对应大小对象。各样堆的堆区都链在一起。至少有多个小目的堆区和3个大目的堆区
- 用来为加载CLLAND而保留。

每种小指标堆总是惟有八个短命区,用来保存gen0和gen1代。那个堆区有或许包含gen2的对象。除了短命区以外,有大概有零个、3个或四个附加的堆区,用来作为gen2堆区并保留gen2对象。

在大指标堆上有三个或多个堆区。

堆区的选取是从低地址早先到高地址,即堆区里低地址对象的时间比高地址对象久。同样下文也有一部分至极意况。

堆区能够按需申请,假如其不包括存活对象就会被剔除,可是堆上发轫的率先个堆区平素都在。对于每种堆,二次提请3个堆区,那几个在给小指标做垃圾回收时和开创大目的时爆发。那样做有更好的属性,因为大目的只会跟gen2一起回收(执行起来代价更高)。

堆区遵照申请的次第链接在一道。链表上最后一个堆区永远是短命区。回收过的堆区(没有存活对象)会被复用而不是直接被删除,也正是变成新的短命区。堆区复用只爆发在小目的堆。每当分配贰个大指标,会考虑任何大目的堆。而小目的的分红只考虑短命区。

托管堆的物理方式

托管堆是一多重的托管堆区。1个托管堆区是GC从操作系统那里申请的叁个连接的内部存款和储蓄器区域。堆区被分为大小对象区,对应大小对象。各个堆的堆区都链在联合署名。至少有二个小指标堆区和三个大指标堆区
- 用来为加载CL奥迪Q5而保留。

种种小指标堆总是唯有三个短命区,用来保存gen0和gen1代。这些堆区有或然含有gen2的靶子。除了短命区以外,有只怕有零个、三个或五个附加的堆区,用来作为gen2堆区并保留gen2对象。

在大目的堆上有叁个或八个堆区。

堆区的接纳是从低地址初始到高地址,即堆区里低地址对象的时刻比高地址对象久。同样下文也有一部分卓殊情形。

堆区能够按需提请,借使其不分包存活对象就会被删除,可是堆上起头的率先个堆区平素都在。对于每一种堆,二遍提请二个堆区,这几个在给小目的做垃圾回收时和创办大目的时爆发。那样做有更好的属性,因为大目的只会跟gen2一起回收(执行起来代价更高)。

堆区依照申请的逐条链接在联合。链表上最终四个堆区永远是短命区。回收过的堆区(没有存活对象)会被复用而不是直接被去除,也正是成为新的短命区。堆区复用只产生在小目的堆。每当分配三个大指标,会设想一切大目的堆。而小指标的分配只考虑短命区。

分红预算

分红预算是跟每种代关联的逻辑概念。那是代里的一个大小限制用来在高于时接触三个GC。

预算是安装在代上依据该代对象存活率的壹特特性。倘诺存活率高,那么预算就会大一部分,那样在下二次GC的时候销毁的靶子和现有的对象有2个更好的比率。

分红预算

分配预算是跟各样代关联的逻辑概念。那是代里的一个大小限制用来在高于时接触3个GC。

预算是设置在代上依据该代对象存活率的2天性质。如若存活率高,那么预算就会大学一年级部分,这样在下叁遍GC的时候销毁的靶子和水保的靶子有叁个更好的比值。

明确回收哪一代

当接触3个GC时,GC必须决定回收哪一代。除了分配预算以外还要考虑以下多少个要素:

  • 代上碎片情形 -
    即使代上的内存碎片很惨重,那么在这么些代上回收产量或者很高。
  • 只要机器上内部存款和储蓄器负荷极大,那么GC会更主动的回收来发生越多的可用空间。那对防止不须求的页面调度很重点。
  • 假如短命堆区没有空间的话,GC会更主动的回收短命对象(越来越多的gen1次收)来制止申请2个新的堆区。

规定回收哪一代

当接触一个GC时,GC必须控制回收哪一代。除了分配预算以外还要考虑以下多少个因素:

  • 代上碎片情形 -
    假如代上的内部存款和储蓄器碎片很严重,那么在这么些代上回收产量大概很高。
  • 假使机器上内部存款和储蓄器负荷十分的大,那么GC会更主动的回收来发生越来越多的可用空间。那对防止不要求的页面调度很要紧。
  • 比方短命堆区没有空间的话,GC会更主动的回收短命对象(更加多的gen贰次收)来防止申请3个新的堆区。

GC的流程

GC的流程

标明阶段

标明阶段的靶子是找出具有存活的靶子。

按代回收的便宜是只须要考虑堆的一有的而不是每回都处理全部指标。当回收短命代时,GC只需求找到那三个代里存活的靶子,那一个新闻由实施引擎上报。除了举办引擎大概引用对象以外,更老一代的指标也可能会引用新一代的靶子。

对于GC使用卡片来标注更老的代。卡片是由JIT帮衬函数在分配操作时设置的。如若JIT帮助函数看到三个指标在短命区的限量,然后设置包罗卡片的字节来提醒其来源于位置。在征集短命区时,GC能够在看堆上设置过的卡片并逐项拍卖卡片对应的指标即可。

标明阶段

标明阶段的靶子是找出全体存活的对象。

按代回收的补益是只必要考虑堆的一片段而不是每一回都处理全部目的。当回收短命代时,GC只须要找到那二个代里存活的目的,那几个消息由履行引擎上报。除了进行引擎可能引用对象以外,更老一代的对象也也许会引用新一代的目的。

对于GC使用卡片来标注更老的代。卡片是由JIT援助函数在分配操作时设置的。假设JIT援救函数看到一个指标在短命区的限定,然后设置包罗卡片的字节来提醒其来源地方。在搜集短命区时,GC能够在看堆上设置过的卡片并相继拍卖卡片对应的对象即可。

计划阶段

布署阶段模拟压缩进程来支配最后的效益,如若缩减效果很好那么GC就会运转削减,不然执行清理。

计划阶段

陈设阶段模拟压缩进度来支配最后的成效,借使缩减效果很好那么GC就会运行削减,不然执行清理。

搬迁阶段

如果GC决定削减,其结果会移动指标,那么对这么些指标的引用必须立异。迁移阶段须求处理全体指向所回收的代中的对象的引用。相比较之下,而标注阶段只处理存活对象因而不须要考虑弱引用(weak
reference)。

搬迁阶段

万一GC决定压缩,其结果会活动目的,那么对这一个目的的引用必须创新。迁移阶段要求处理全数指向所回收的代中的对象的引用。比较之下,而标注阶段只处理存活对象因而不必要考虑弱引用(weak
reference)。

压缩阶段

以此等级很直观,因为在安顿阶段就早已总括对象应当移动的新鸿基土地资金财产点,压缩阶段只必要将指标拷贝过去。

缩减阶段

其一阶段很直观,因为在布置阶段就已经总计对象应该移动的新鸿基土地资金财产方,压缩阶段只须求将对象拷贝过去。

清理阶段

理清阶段会翻动三个存活对象之间的空间。其为那个空中创立闲置对象。相邻的搁置对象相会并。它会将富有的闲置对象保存在 闲置对象列表(freelist)

清理阶段

理清阶段会翻动四个存活对象时期的空间。其为那几个空中创设闲置对象。相邻的搁置对象会计统计一。它会将享有的闲置对象保存在
闲置对象列表(freelist)

代码流程

术语:

  • WKS GC: 工作站 GC.
  • SRV GC: 服务器 GC

代码流程

术语:

  • WKS GC: 工作站 GC.
  • SRV GC: 服务器 GC

效率行为

效果行为

WKS GC并关闭了并行GC

  1. 用户线程用完了分红预算并触及三个GC。
  2. GC调用SuspendEE来刹车托管线程。
  3. GC决定回收哪一代。
  4. 履行标注阶段。
  5. 执行布署阶段并控制是还是不是要实施加压力缩。
  6. 即使要缩减则履行迁移和压缩进程。不然执行清理进程。
  7. GC调用RestartEE来过来托管线程。
  8. 用户线程复苏执行。

WKS GC并关闭了并行GC

  1. 用户线程用完了分红预算并触及三个GC。
  2. GC调用SuspendEE来刹车托管线程。
  3. GC决定回收哪一代。
  4. 履行标注阶段。
  5. 施行布置阶段并控制是不是要推行压缩。
  6. 若是要压缩则执行迁移和压缩进程。不然执行清理进程。
  7. GC调用RestartEE来恢复生机托管线程。
  8. 用户线程苏醒执行。

WKS GC并打开了并行GC

那几个验证了二个后台GC是什么进行的:

  1. 用户线程用完了分红预算并触及二个GC。
  2. GC调用SuspendEE来刹车托管线程。
  3. GC决定是或不是供给后台GC运行。
  4. 比方急需后台GC,唤醒它。后台GC线程调用RestartEE来回复托管线程的实践。
  5. 托管线程在后台GC执行的还要运营并分配内存。
  6. 用户线程也许会用完分配预算并触及2个短跑代GC(大家誉为前台GC)。那些进度跟“WKS
    GC并关闭了并行GC”一样。
  7. 后台GC再度调用SuspendEE来完毕标注并调用RestartEE来在用户线程运营的还要并行执行清理阶段。
  8. 后台GC处理达成.

WKS GC并打开了并行GC

这几个验证了3个后台GC是哪些执行的:

  1. 用户线程用完了分红预算并触及叁个GC。
  2. GC调用SuspendEE来刹车托管线程。
  3. GC决定是不是供给后台GC运转。
  4. 假定急需后台GC,唤醒它。后台GC线程调用RestartEE来回复托管线程的推行。
  5. 托管线程在后台GC执行的还要运转并分配内部存储器。
  6. 用户线程可能会用完分配预算并触及3个短距离赛跑代GC(大家誉为前台GC)。这些历程跟“WKS
    GC并关闭了并行GC”一样。
  7. 后台GC再一次调用SuspendEE来完结标注并调用RestartEE来在用户线程运转的还要并行执行清理阶段。
  8. 后台GC处理完结.

SVLacrosse GC并关闭了并行GC

  1. 用户线程用完了分配预算并触及三个GC。
  2. 服务器GC线程被提醒冰调用SuspendEE来刹车托管线程。
  3. 服务器GC线程执行GC工作(与WKS GC并关闭了并行GC一样).
  4. 服务器GC线程调用RestartEE来复苏托管线程。
  5. 用户线程苏醒执行。

SV奥迪Q5 GC并关闭了并行GC

  1. 用户线程用完了分红预算并触及三个GC。
  2. 服务器GC线程被提拔冰调用SuspendEE来刹车托管线程。
  3. 服务器GC线程执行GC工作(与WKS GC并关闭了并行GC一样).
  4. 服务器GC线程调用RestartEE来过来托管线程。
  5. 用户线程苏醒执行。

SVOdyssey GC并开拓了并行GC

那一个境况跟WKS GC并打开了并行GC一样,除了在服务器GC线程上从不后台GC。

SV汉兰达 GC并开拓了并行GC

本条情景跟WKS GC并打开了并行GC一样,除了在服务器GC线程上没有后台GC。

物理架构

那么些章节用来补助你知道代码进程。

用户线程用完定额之后,通过try_allocate_more_space申请新定额。

try_allocate_more_space在须求触发GC时调用GarbageCollectGeneration。

就算WKS
GC并关闭了并行GC,GarbageCollectGeneration在触发GC的用户线程上执行,代码进程如下:

 GarbageCollectGeneration()
 {
     SuspendEE();
     garbage_collect();
     RestartEE();
 }

 garbage_collect()
 {
     generation_to_condemn();
     gc1();
 }

 gc1()
 {
     mark_phase();
     plan_phase();
 }

 plan_phase()
 {
     // actual plan phase work to decide to 
     // compact or not
     if (compact)
     {
         relocate_phase();
         compact_phase();
     }
     else
         make_free_lists();
 }

一旦WKS GC并开拓了并行GC(默许情形),后台GC的代码进程如下:

 GarbageCollectGeneration()
 {
     SuspendEE();
     garbage_collect();
     RestartEE();
 }

 garbage_collect()
 {
     generation_to_condemn();
     // decide to do a background GC
     // wake up the background GC thread to do the work
     do_background_gc();
 }

 do_background_gc()
 {
     init_background_gc();
     start_c_gc ();

     //wait until restarted by the BGC.
     wait_to_proceed();
 }

 bgc_thread_function()
 {
     while (1)
     {
         // wait on an event
         // wake up
         gc1();
     }
 }

 gc1()
 {
     background_mark_phase();
     background_sweep();
 }

物理架构

以此章节用来支持您了然代码进度。

用户线程用完定额之后,通过try_allocate_more_space申请新定额。

try_allocate_more_space在须求触发GC时调用GarbageCollectGeneration。

如果WKS
GC并关闭了并行GC,GarbageCollectGeneration在触发GC的用户线程上实行,代码进程如下:

 GarbageCollectGeneration()
 {
     SuspendEE();
     garbage_collect();
     RestartEE();
 }

 garbage_collect()
 {
     generation_to_condemn();
     gc1();
 }

 gc1()
 {
     mark_phase();
     plan_phase();
 }

 plan_phase()
 {
     // actual plan phase work to decide to 
     // compact or not
     if (compact)
     {
         relocate_phase();
         compact_phase();
     }
     else
         make_free_lists();
 }

一经WKS GC并开拓了并行GC(暗许情形),后台GC的代码进度如下:

 GarbageCollectGeneration()
 {
     SuspendEE();
     garbage_collect();
     RestartEE();
 }

 garbage_collect()
 {
     generation_to_condemn();
     // decide to do a background GC
     // wake up the background GC thread to do the work
     do_background_gc();
 }

 do_background_gc()
 {
     init_background_gc();
     start_c_gc ();

     //wait until restarted by the BGC.
     wait_to_proceed();
 }

 bgc_thread_function()
 {
     while (1)
     {
         // wait on an event
         // wake up
         gc1();
     }
 }

 gc1()
 {
     background_mark_phase();
     background_sweep();
 }

资料

资料

相关文章