evacuation(evacuation什么意思中文翻译)

  • 时间:
  • 浏览:76
  • 来源:奥一装修网

brilliantly

本文主要摘自Garbage-First垃圾收集一文。通过本文,我大致了解了G1收集器的工作原理,也了解了Rset​​,起初并没有特别了解它,因此翻译是一个注释,其中大部分是原始文本的文字翻译,因此省略了为了理解不太相关的内容,我还添加了我自己对阅读时难以理解的要点的理解。必须有一些错误。如果读者发现它们,请指出。 Abstract G1是面向服务器的垃圾收集器。它主要用于在多处理器,大内存服务器中尽可能提供软实时和高吞吐量垃圾收集。基于整个堆的操作(例如全局标记)与工作线程并发执行(变异(使用Mutator表示工作线程)),以避免由更大的堆或更多的活动数据引起的长堆。时间被打断了。并发标记使用压缩疏散(单词不容易翻译,我觉得翻译更准确,实际上,该操作是将分区中的实时数据迁移或复制以回收到新分区)垃圾收集和分区年龄增长。迁移还通过并行使用多个线程来提高吞吐量。 1简介Java语言通常用于在服务器端编写大型应用程序。这些应用程序的特点是尚存大量数据,多线程并在强大的多处理器上运行。显然,吞吐量对于这些应用程序很重要。此外,这些应用程序还具有一定的响应时间要求,例如电信提供商的呼叫处理程序,如果延迟很大,会使客户感到不满意。 JLS使用垃圾回收来回收无用的存储。传统的“停用词”垃圾收集器将影响应用程序的响应能力,因此需要并发和增量垃圾收集器。这些垃圾收集器通常会牺牲一些吞吐量,以减少暂停时间。因此,我们允许用户指定软实时目标。例如,在y ms的时间片中,由于垃圾回收引起的暂停不得超过x ms。通过指定这些明确的目标,但这不会降低吞吐量或增加垃圾收集周期(占地面积)。本文介绍的G1垃圾收集算法专用于在具有大内存,高分配率和多个处理器的计算机上满足如此弱的实时目标,并保持高吞吐量。 G1垃圾收集器通过多种技术实现了这些目标:将整个堆分为相同大小的列(区域)区域,并且记忆集(记住Rset)用于记录指向分区的应用程序。它可以是从老一代到年轻一代,反之亦然(有一些例外,稍后将介绍)。双向内存集可实现任意分区的垃圾回收。为了使Rset状态保持最新,Murtator使用特殊的写屏障来创建Rset更新日志记录。这些记录由并发线程处理,从而使垃圾回收时间变短。 G1垃圾收集器使用快照快照(SATB)并发标记算法。 SATB会定期分析全局可达性以确保一定的完整性-最终可以识别所有垃圾。并发标签还计算每个分区的实时数据数。该信息可用于指导垃圾收集分区的选择:具有较少实时数据和更多垃圾的分区将更有效地进行垃圾收集,这就是派生“垃圾优先”名称的原因。 SATB标记算法还引入了更少的暂停。 G1垃圾收集算法使用新机制来实现实时目标。现有的硬实时垃圾收集器以复制单个对象的粒度收集中断,以满足硬实时约束,这会引入一定量的时间和空间开销。相反,G1以较粗的粒度(尤其是疏散)复制对象。 G1垃圾收集器提供了一个准确的模型,可以基于可以快速测量的分区的某些属性评估分区回收的成本,因此垃圾收集器可以选择在给定的暂停时间可以回收的那些分区(至少大多数时间满意)。 G1垃圾收集器的目标是放弃这种硬实时保证,并确保更好的吞吐量和空间利用率,这也是许多应用程序要求的折衷方案。 2数据结构/机制本节介绍G1使用的数据结构和相关机制。 2。1堆布局/分区/分配G1垃圾收集器将整个堆分为许多大小相等的区域,每个区域都包含连续范围的虚拟内存空间。分配在堆分区中是为了增加由top划分的已分配和未分配空间的边界。当前正在分配的分区称为当前分配区域。因为我们主要关注多线程处理器,所以每个Mutator线程都会通过CAS操作从堆中分配线程本地分配缓冲区(TLAB),并在运行过程中向其自身分配线程生成的新对象。分配过程中的竞争较少。当当前分配的分区已满时,将选择一个新分区进行分配。可用分区通过链接列表进行组织,因此可以在恒定时间内完成新分区的选择。 大对象也可以在TLAB之外的当前已分配分区中直接分配。大于堆分区四分之三的对象称为大型对象。大量对象分配在许多专用的连续分区中。这些分区仅用于分配巨大的对象。 2。2内存集(Rset)的维护每个分区都有一个Rset,用于记录引用该分区中(活动)对象的点(指针)。维护这些对象需要Mutator线程在修改可能导致跨分区引用时通知垃圾回收器。这些通知是通过卡表实现的:堆中的每个512字节都映射到卡表中的字节条目。每个线程还具有关联的Rset日志,该日志用于记录对卡的更改。每个线程的当前日志已满后,它将被放置在全局日志中,因此有一系列已填充的RS缓冲区。 Rset本身也是卡哈希表,实际上是因为并发,为了减少并发冲突,每个分区将与多个卡表关联。在每次引用(指针)写入后执行内存集写屏障(Rset写屏障)。例如,在代码中,执行参考写操作xf = y,并且寄存器rX和rY保留x和y的地址。然后,此写操作后的屏障伪代码如下:1 | rTmp:= rX XOR rY2 | rTmp:= rTmp》》 LogOfHeapRegionSize3 | //下面是有条件的移动instr4 | rTmp:=(rY == NULL),然后0,否则rTmp5 |如果(rTmp == 0)转到filter6 |致电rs_enqueue(rX)7 |已过滤:如果在写操作之后执行xf,则指向的对象y和x位于一个分区中,也就是说,没有跨分区引用它们,因此无需将此类写操作记录在Rset中。在上述伪代码中的第1行,第2行进行XOR操作和移位操作之后,rTmp = 0意味着x和y在同一分区中。第4行过滤空指针。如果写操作通过了这些过滤条件,则意味着写操作是在分区之间执行的。 rs_enqueue首先读取rX所在对象的卡表条目(条目)。如果条目已经很脏,则操作将结束而无需再次设置。这种判断避免了由于多次写入同一位置而导致的多次更新。如果条目不是脏的,它将被设置为脏状态,然后将指向该卡的指针放置在线程的Rset日志中。如果线程Rset日志已满(默认情况下为256个元素),则该日志将添加到填充缓冲区的全局集合中,然后将为该线程分配一个新的缓冲区。 一旦全局满缓冲区中包含的满缓冲区数量达到配置的阈值(默认值5),等待的并发记忆集线程将开始处理。并发内存集线程将全局缓冲区视为队列,对于全局完整缓冲区中的每个缓冲区,处理线程依次处理缓冲区中的每个卡表指针。指向经常引用的对象的卡被认为是热门的。为了避免频繁处理此类卡,G1垃圾收集器会尝试识别频繁写入的地址所在的卡,并将该​​地址的处理推迟到下一个迁移阶段。 (撤离暂停)。 G1通过添加另一个卡表来记录自上一个迁移阶段以来该卡变脏的次数,从而识别出一个热卡。每次处理卡时,卡变脏的次数都会增加。一旦次数超过配置的阈值(默认为4),则将卡添加到称为热队列的特殊缓冲区(默认大小为1k)。热队列在每个迁移阶段的开始进行处理,因此热队列在迁移阶段结束时变为空。如果热队列已满,将从中删除卡并进行处理。 总而言之,并发内存集线程处理不热的卡,并从热队列中删除卡。在处理卡时,首先将与卡表相对应的条目状态设置为clean,这样,如果其他线程再次写入与卡条目相对应的地址,则可以将它们再次设置为脏状态,并将其放回原位。日志。 。然后,并发内存集线程检查对与卡条目相对应的所有对象的所有引用(对象的域也可以是引用),找到可能导致卡设置为脏状态的那些引用修改,并找到那些具有指向其他分区的指针。指针(如果找到)将卡插入被引用对象所在的分区的Rset中(注意:分区的Rset记录引用该分区中对象的其他分区的卡)。 我们只使用一个并发内存集线程。当有空闲处理器时,Rset处理将同时执行。如果线程不能及时处理Rset缓冲区,即处理速度不如Mutator线程的写缓冲区那么快,则缓冲区将变得特别大。因此,我们限制了缓冲区的大小,并且Mutator也将添加到缓冲区中以至于为时已晚。 在适当的时候,我们将挂起所有Mutator线程并开始迁移阶段。在迁移阶段,我们将选定集合集分区中的活动对象复制到堆中的另一个分区,并释放集合集分区的空间。迁移阶段的存在是压缩空间(压缩空间碎片),并且对于Mutator,对象的移动必须是原子的。在并发环境中维护此类原子特性的成本相对较高,因此STW(停用词)方法用于迁移阶段。 在多处理器,多线程应用程序中使用串行垃圾回收器可能会导致性能瓶颈,因此我们将尽可能使用多线程并发迁移操作。 迁移操作的第一步是选择适当的系列集合。然后,迁移阶段的主要操作开始,GC线程开始扫描将来可以处理的Rset缓冲区,以更新分区Rset,扫描Rset和其他根节点以确定尚存的对象,最后迁移那些尚存的对象对象到新分区。这些动作之间没有明确的同步,但是要确保每个操作只能由一个线程处理。 为了加快迁移过程中的并发分配,我们使用GCLAB,并且多个线程将尝试将迁移指针安装安装在要回收的同一分区上。唯一成功的安装程序将负责复制和扫描分区中的对象并对其负责。执行迁移和回收。为了实现负载平衡,使用了工作窃取机制。 图1 Remembered Set Operation。png如上图1所示,分区R1的内存集记录了分区R0和R1对其分区中对象的引用。分区R1迁移到分区R3。由于是垃圾,因此将其收集起来,因此R3分区的Rset仅记录分区R2中仍然存在的c和b的引用。在并发标记阶段,分区R0中的对象被标识为垃圾。 2。4世代G1世代垃圾收集算法具有许多优点。与较旧的对象(寿命长的对象)相比,新分配的对象更可能是垃圾。结果,由于经常需要初始化新的分配对象,因此需要更新其他分区的Rset。我们可以在G1垃圾回收中利用这些功能。当选择一个分区作为Mutator线程当前分配的分区时,我们可以将其标识为年轻分区,该分区将被选择到集合集中以进行下一轮迁移。可以迁移的新对象(不是垃圾)在迁移后会被扫描出去(此处未提及目的,个人理解可能是更新分区的Rset)。 请注意,集合集可以同时包含年轻分区和非年轻分区。 G1垃圾收集有两种模式:世代G1和纯G1。生成模式是默认模式。 代代模型有两个子模式:在迁移阶段,您可以选择仅迁移年轻分区(完全),也可以选择同时迁移年轻和非年轻分区(部分)。完全模式将并且只会将所有新分区添加到集合集中。部分将所有年轻分区添加到集合集中。在满足软实时要求(允许暂停时间)的同时,还可以添加非新分区。将年轻分区添加到集合集以进行迁移。

unrelenting

2。5并发标记并发标记是G1垃圾收集中非常重要的阶段。并发标记过程不需要选择分区作为收集集的顺序性质。它将提供有关分区中实时数据的信息,进而将实现垃圾优先收集策略。 G1使用开始时快照(SATB)算法进行并发标记。这样,通过在标记开始处拍摄对象图的快照,可以确保在标记开始处被标识为垃圾的对象始终是垃圾对象(这是此翻译的字面意思,但个人含义一开始的理解应该是快照。整个标记完成后,图中的幸存对象仍然是幸存对象,即使在标记过程中它变得不可到达,稍后引入的标记写障碍也是为了确保这一点。这些对象需要标记为活动对象,但是由于它们在开始时并不是快照对象图中的对象,因此无需跟踪它们,这大大降低了并发标记的成本。 2。5。1标签数据结构我们维护两个标签位图(每个分区两个),分别称为上一个和下一个。上一个位图是最后一个标记之后的位图,并记录最后一个标记之后的剩余对象。下一个位图可能正在构建中。每个标记结束后,上一个和下一个位图将交换身份,下一个位图将成为上一轮的下一轮维护,并且将构造下一轮的下一个位图。位图中的每一位记录一个对象的起始地址。 2。5。2初始标记阶段/并行标记标记周期的第一阶段是清除所有分区的下一个位图。然后,初始标记阶段将停止所有Mutator线程,并将标记从根节点直接可访问的所有对象(在世代模式下,初始标记将在完整的年轻收集集的迁移操作中完成)。每个分区在标记开始处(TAMS)变量将具有一个顶部,一个用于前一个位图位置,一个用于下一个位图位置。上一个TAMS和下一个TAMS变量将代替后面的这两个变量使用。这两个变量用于区分在标记过程中分配的对象,以便在标记过程中通过分片操作不会减慢位图的更新。 图2通过TAMS variables。png进行隐式标记如图2所示,初始标记阶段将遍历所有分区,并将当前在每个分区的位图中分配的位置顶部复制到下一个TAMS。图2中的A和D复制了顶部,B和E显示了在标记过程中分配的对象将位于下一个TAMS变量之上,并将被直接视为活动对象。 将所有top复制到下一个TAMS之后,Mutator线程重新启动,并且标记循环的并发阶段开始。 2。5。3并发标记写入障碍由Mutator可以修改由并发标记启动的并发快照。这破坏了SATB算法的原理。因此,SATB算法要求Mutator线程在覆盖引用时记录引用所指向的对象(这可以确保以前引用的对象仍然可以访问)。下面我们列出了伪代码,即在rX地址FieldOffset处的写屏障的参考屏障为rY(即xa = y):1 | rTmp:=负载(rThread + MarkingInProgressOffset)2 |如果(!RTmp)转到filter3 | rTmp:=负载(rX + FieldOffset)4 |如果(rTmp == null)转到filter5 |调用satb_enqueue(rTmp)6 |已过滤:执行完上述伪代码的逻辑后,将执行指针存储操作【rX,FieldOffset】:= rY,将FieldOffset处的应用程序从rX偏移到rY地址处的对象。伪代码中的第1行和第2行用于确定当前正在进行的同时标记过程。如果不是,则不需要执行以下记录工作。在许多应用中,此步骤可以避免大多数障碍的实现。第3行用于从rX获取FieldOffset处的对象,而第4行用于过滤空对象。在许多应用程序中,指针通常被初始化为预定义的空引用,因此可以过滤许多空值。 satb_enqueue操作将rX Offset FieldOffset的原始值记录到当前线程的标记缓冲区(与内存设置缓冲区相同)。如果标记缓冲区已满,则线程的标记缓冲区将添加到全局完整标记缓冲区中。并发标记线程将定期检查全局完整标记缓冲区的大小。如果太大,它将终止遍历堆的过程并处理标记缓冲区。 此处的写屏障主要是为了在修改并发Mutator线程后使SATB开头的快照中的可访问对象可访问,例如快照中的x = y,但是由于它在标记期间是并发的,因此可能在标记过程中。 Mutator将执行x = z,因此,通过标记写屏障,在实际分配x = z之前,将x最初指向的y记录到缓冲区中,然后执行实际x = z的分配。这样,仍可以将y计为有效(可访问),从而确保快照的性质。 2。5。4最终标记暂停完成所有标记对象的扫描并处理所有并发标记写屏障写入的所有缓冲区后,并发标记完成。扫描所有标记的对象很容易确定其是否完整,但是由于Mutator线程不会在填充缓冲区之前将缓冲区放入全局缓冲区,并且并发线程将仅处理全局缓冲区中的日志,而后者则不然如此容易确定是否完成。并发标记采用STW方法只是为了能够可靠,正确地判断缓冲是否全部完成。使用STW方法,将完全处理全局完整缓冲区中的所有未处理缓冲区,并且也将以相同方式处理未填充缓冲区。这些处理是同时执行的,因此可以避免由于过多的Mutator未满和并发标记写入屏障缓冲区而导致的长时间停顿。 2。5。5生存统计(计数)和清除并发标记将是为每个分区标记的对象数。最初,此操作作为标签的一部分执行。但是,在迁移阶段,迁移活动对象时必须更新每个分区中活动对象的数量。当使用多个线程进行迁移操作时,多个线程可能会同时将活动对象迁移到同一分区。存活对象的数量可能形成多线程竞争。可能有许多相关技术可以解决此问题,但是即使只有一个线程更新分区中活动对象的数量,也将导致巨大的成本。因此,在最后的标记阶段结束之后,GC线程将重新扫描每个分区以对当前标记的TAMS变量下的对象进行计数。这似乎是清除阶段的工作,但请注意,我们此时仅通过扫描标记位图来扫描幸存的数据,而不是遍历所有垃圾对象。 A将在2。6节中介绍,当分区的下一个TAMS正在更新时,在迁移阶段可能会有一个标记线程。最后的清理阶段还将以多种方式完成标记。在此阶段,上一个和下一个位图交换身份:最近完成的位图成为前一个位图。另外,由于标记已完成,因此每个分区的下一个TAMS变量的值将被复制到该分区的前一个TAMS变量,如上面图2中的C和F所示。需要在先前的位图和先前的TAMS变量中查询生存数据信息,因此标记后新生成的标记信息将用于确定对象是否存在。在上面的图2中,浅灰色是扫描的死对象,D和E显示了在最后的标记完成之后如何在正在进行的新标记阶段中使用信息。 最后,清理暂停将根据预期的GC效率对分区进行排序。在此,将可回收垃圾的估计数量除以分区的回收成本被用作评估标准。这里的成本与几个因素有关,例如,估计迁移剩余数据的成本,遍历分区的Rset的成本等。(3。2。1将讨论评估分区恢复的成本的内容) 。此处对分区进行排序只是对集合集的初始排序,如3。3中所述,成本估算将随时间而变化,因此此处的估算仅是初始估算。 这些不包含任何实时数据的分区将在此阶段直接回收。对于某些应用程序,此步骤可以回收大量的垃圾。 2。6疏散暂停和标记在本节中,我们将讨论迁移阶段和并行标记阶段的两个主要相互作用。 首先,迁移阶段不会迁移在标记阶段确定为非活动的那些对象。因为该对象是无效对象,所以很明显,该对象不会被任何根节点(直接或间接)引用,但是该对象可能会被其他无效对象引用。因此,只需跟踪对这些活动对象的引用即可。从其他分区到集合集分区中对象的跨分区引用由集合集分区的Rset标识。不会被迁移。 第二,在迁移阶段迁移对象时,需要确保正确标记了对象。如有必要,我们可以同时参考上一个和下一个位图。这里的机制有点复杂,但是它的空间有限并且将不再介绍。 。 当标记线程的工作线程不为空​​时(意味着标记线程仍在标记,并且标记尚未完成),我们允许进行迁移操作。如果在标记线程完成之前不允许迁移操作开始,则可以禁用迁移阶段。预计的延迟(影响垃圾回收,并可能导致完整的gc)。标记线程的工作堆栈中的对象可以引用集合集分区中的对象。因为这些工作堆栈中的对象已被标记,所以这些对象必须在先前的位图中处于活动状态,因此这些对象也将被迁移。为了确保正确处理标记线程工作堆栈中的对象,我们还将标记线程工作堆栈中的对象用作根。 2。7流行对象处理当被称为流行对象时,许多对象都引用该对象。本节讨论如何处理流行的对象以实现以下目标:减小Rset大小和更有效的内存集写障碍。 我们维护一些分区,这些分区专用于将流行对象存储在堆的前端。我们希望快速识别流行的对象并将其隔离在这些前缀分区中。这些分区将不会被选作回收的集合集分区。 当我们同时更新分区Rset时,如果分区的Rset大小超过指定的阈值,则分区将进入流行对象处理阶段(流行暂停),因为Rset太大通常意味着存在流行对象Objects from其他分区被多次引用。流行对象处理阶段首先计算分区中每只大象被引用的近似次数,然后将超出指定的单个对象流行度阈值引用的那些对象迁移到存储流行对象的前缀分区。如果没有引用对象的次数,则迁移不会发生,但是每个分区的阈值将加倍,以避免很快再次触发流行对象处理阶段。 对流行物体进行特殊处理有两个好处。由于我们不会迁移放置在前缀分区中的流行对象,后来的实验证明,这将大大减少Rset中的条目数。我们还通过过滤常用对象来减少Rset的处理开销。我们将更新2。2节中的内存集写入部分,以过滤空引用代码,如下所示:if(rY这将同时过滤空引用和流行对象。当对流行对象执行特殊处理时,可能会带来可观的损失。好处,但在某些应用程序中可能没有任何好处,因此这里的特殊处理需要选择使用

bulldozer

3启发式在上一节中,我们定义了G1垃圾收集器中使用的相关技术,在本节中,我们介绍了G1使用的启发式算法。3。1进入G1垃圾收集器的基本前提是两个用户指定的参数:堆大小的上限。一个软实时目标,即用户指定的时间片)此时间段可接受的大小和最大GC暂停时间。此外,用户还可以指定垃圾回收是否使用世代模型(第2。4节)。将来,我们希望可以动态指定此参数。 当我们追求设定最大暂停时间的目标时,我们仅计算STW暂停时间。这些并发操作将不计为垃圾回收。耗时的。在多处理器机器上,我们还假定由垃圾回收引起的开销由所有Mutator线程“共享”。 3。2满足软实时目标软实时目标是垃圾收集过程中的主要约束(或目的)。我们需要清楚的是,G1垃圾收集算法不是硬实时垃圾收集器,我们只是尽力满足软实时目标。为了满足软实时目标,我们需要保证两点:(1)保证单次暂停不要超过设定的目标。 (2)您需要计划在指定时间段内的暂停次数。太多次将导致无法达到既定目标。下面我们将讨论如何满足这些条件。 3。2。1预测迁移暂停时间为了确保指定的暂停时间不在线,我们需要仔细选择“集合集”分区以确保其可以按时完成收集。我们有一个模型,可以预测将分区添加到要收集的集合集的成本。在世代模型中在完全年轻模式下,收集集中的所有分区都是年轻分区。由于一定数量的年轻分区被迫加入集合集,因此我们必须能够预测回收这些数量的分区所需的时间。通过计算历史完整的年轻代模型平均恢复成本,我们确定将两个迁移操作之间生成的年轻分区添加到集合集中。 在部分年轻模式下,如果时间允许,我们将添加一定数量的非年轻分区。当确定无法满足驻留时间时,我们将停止向收集集中添加分区。 在以下情况下,我们用于评估集合集的迁移成本,如下所示:公式中所用符号的含义如下::集合集的回收成本:对于所有形式的暂停都是相同的。 :是扫描卡的平均成本,它是Rset为了更新必须扫描的脏卡的数量。 :是扫描记录以指向当前回收分区参考的卡的成本,并且是分区的内存集Rset中卡条目的数量。 :是按字节统计信息迁移(和扫描)实时数据的成本,并且是分区中实时数据占用的大约字节数。上式中的参数以及实现算法和运行应用程序的平台在一定程度上还取决于应用程序本身。在操作开始时,我们将保守地设置这些值以满足驻留时间要求。在程序的运行过程中,我们将根据运行的统计数据细化(细化)这些参数的值。为了减少程序更改对这些参数值的影响,我们为每个参数计算了一系列值,然后使用一定的置信区间来调整参数。 可以计算剩余的参数以及其他使用的参数(至少是估计值)。例如,分区中的活动数据字节数可以由最后的并发标记计数。最后一个并发标记通常为分区提供最大字节数。我们将保守地使用此上限作为分区字节数的估计。我们基于最近分配的分区的生存率的统计信息估计尚存的字节数。为了尽可能准确地评估活动字节数,我们记录了一系列生存率,并根据用户指定的置信度进行了预测。 对于并发标记引起的STW暂停,我们不能控制太多,只能尽最大努力降低成本。 3。2。2安排暂停以实现实时目标上面我们介绍了如何满足暂停时间要求。为了满足暂停透视图的要求,需要做的第二点是使GC暂停时间不超过每个时间片的暂停时间要求。 G1垃圾收集算法的一个重要功能是,只要有足够的空间,我们就会始终推迟垃圾收集操作:我们将推迟标记和迁移操作,并且如果有必要,我们将扩大堆大小直到设置为set达到最大限制。当必须推迟年轻的迁移以满足驻留时间要求时,为了避免下一次迁移操作超过时间限制,我们可以让Mutator在非年轻分区中分配新分配的对象。暂停时间的计划是通过记录最近时间段中的GC开始/ GC停止时间以及该时间段中的总STW时间来实现的。通过这些统计信息,我们可以轻松解决以下问题:在不超过暂停时间的情况下,当前可以暂停的最长时间是多少?什么时候最早可以进行新的STW停转操作? 3。3集合集选择在本节中,我们讨论如何在某些年轻模式下选择要添加到集合集的分区。如2。5节所述,回收分区的效率等于该分区中的垃圾量除以回收垃圾的估计成本。我们使用与计算相同的方法来估计垃圾量。应当注意,一个分区可能只有很少的实时数据,但是由于其Rset太大,因此处理和恢复效率很低。我们的目标是对所有可回收分区进行分类,以降低回收效率。 在标记阶段结束时,我们将根据回收效率团队划分进行排序。但,特别是,分区的Rset也将增加。在迁移阶段开始时,将根据初始估计的恢复效率对一些指定数量的可用分区进行排序,然后在操作更改后根据效率估算再次对这些分区进行排序。这时,我们将考虑这些分区是基于整理出来的恢复效率。 当估计的暂停时间将超过设置的限制,或者没有足够的空间容纳迁移的实时数据时,我们将停止从有序分区中选择分区以添加到收集集中。当然,当迁移失败时,我们也有相关的机制来处理。 3。4迁移阶段初始化在世代和纯G1模式下用于迁移阶段初始化的启发式算法非常不同。 首先,在所有模式下,我们将选择分区大小的比率作为硬边距和硬限制。因为我们使用迁移来回收分区,所以我们必须确保有足够的空间来容纳需要迁移的实时数据。难的余地是确保该空间的存在。因此,当当前空间使用量达到硬限制时,必须执行迁移操作。当前的硬边距是一个常数,将来应该可以动态调整。例如,如果我们知道允许的最大暂停时间以及每个字节的迁移(复制)成本,那么我们就可以知道在一定时间内迁移一定数量的存活对象锁所需的最大空间。 在完全年轻的G1模式下,我们将继续估算可在允许的暂停时间内回收的分区数量。每当应用程序分配此数量的分区时,都会启动一轮迁移操作。对于状态应该相对稳定(稳态)的应用程序,此功能将使其迁移暂停具有一定的周期性。如果回收间隔大于指定的时间片,则可以满足软实时要求。在某些年轻模式下,只要暂停时间允许,我们就会频繁地开始迁移阶段。通过在不超过暂停时间限制的情况下开始尽可能多的迁移阶段,可以减少添加到集合集中的年轻分区的数量。3。5并发标记初始化在分代模式下,用于启动并发标记的启发式算法很简单。我们定义另一个软边距和一个软限制。当堆空间使用量超出软限制,并且如果暂停时间允许,我们将在暂停后尽快初始化并发标记。像硬边距一样,软边距目前是一个常数,但将来也会进行动态调整。设置软限制的目的是确保并发标记完成时不超过硬限制。 在完全年轻模式下,迁移阶段与并发阶段之间的交互更加有趣。我们将使用标记阶段提供的信息来最大化标记阶段和后续一系列迁移阶段的累积效率。标记分区还会回收所有分区,这些分区的分区在一定价格内为垃圾。标记阶段之后的第一个收集是具有最高收集效率的分区,因此此类收集将提高累积收集效率。随后的回收根据回收效率进行排序,因此回收效率不是很高,会降低累积回收效率,因此累积效率会先增加到最大值,然后开始下降。此时,我们将开始新的标记阶段。对于应用程序的状态(稳态)没有特别更改的应用程序,每个标记和随后的迁移阶段都是相似的,并且具有一定的周期性。总体而言,迁移效率将与第一次恢复的效率相似,即更高。 4模拟实验(略)5相关工作(略)6总结(略)