阿苏尔的“无休止的”垃圾收集器的解释
我刚刚读过这个:
http://www.artima.com/lejava/articles/azul_pauseless_gc.html
虽然我有编译器的一些经验,但我没有做任何有关垃圾收集的事情。 对我来说是一个很大的黑盒子。
我一直在努力去理解这篇文章提到的问题。 我理解这个问题(执行大多数垃圾收集器时有一个暂停),我明白他们声称他们的实现没有这个问题。 但是我不明白为什么这个问题首先出现(这个问题似乎被认为是在原文中被理解了),结果我不明白他们的解决scheme为什么会起作用。
有人可以向我解释:
- 为什么垃圾收集者有一般的停顿
- 为什么Azul的gc没有这个问题?
我倾向于在graphics解释的时候更好地理解这种事情 – 可能使用代码编辑器完成的小内存模式就足够了。
谢谢!
他们谈论压缩堆时不可避免的停顿。 你看,当你分配和释放大量不同大小的对象的时候,你会把堆分割(就像分割你的硬盘一样)。 当碎片变得太过分了时,你必须通过保留一大块内存来清理/碎片整理/压缩堆,将所有对象移动到那里(没有任何碎片),并将它们以前的位置作为一个新的内存块而没有任何对象即不分割。
当你这样做的时候,你把对所有移动物体的所有引用无效化。 为了防止这种情况,您必须防止使用引用预压缩对象位置的引用。 最简单的方法是暂停整个应用程序,移动对象然后去更新所有的引用。 当然这可能会产生很大的开销。
所以Azul提出的解决scheme是这样的:他们build立了一个“读屏障”,允许GC拦截解引用,这样他们可以懒洋洋地更新实际使用的引用。
为什么垃圾收集者有一般暂停?
GC通过从一组全局根(全局variables,线程堆栈和CPU寄存器)开始追踪可达堆块来工作。 地理信息系统从快照到即时的滑动比例。 快照GC根据全局根和堆拓扑的快照工作。 随着增值器运行,即时GC逐渐更新对堆的解释。
追查不是“为什么垃圾收集者总体上停顿一下”,有更大的停顿原因:对象搬迁是主导的。
但是,对于快照跟踪器及其相对效率来说:即时跟踪对于初始快照跟踪器可以更有效。 你在描述[VCGC]时提到的同一篇论文将Azul的以前的非世代Pauseless收集器归类为一个精确的波前[3]示踪剂:
“…大多数实际的collections家使用波阵面的保守抽象,而不是这里提供的精确定义,也就是说,波阵面是以物体粒度来追踪的,然而,精确的波阵面不仅仅是理论上的,而且最近在硬件Azul Java服务器的辅助收集器,在每个指针[2]中都有一个“未标记”位。
阿祖尔的C4分享这个质量,但实现它使用纯软件,自我修复LVB读障碍。
完全快照GC获得高吞吐量,因为收集器几乎完全独立于增变器运行,但是由于拍摄快照导致暂停,所以具有高延迟。 完全即时的GC获得低延迟,因为一切都是逐步完成的,但吞吐量较低,因为增变器和GC之间的细微沟通。
一个精确的波前示踪剂(从本文中讨论的“不需要花费时间在不需要的物体上”的angular度)是一种有效的示波器,根据定义,它也具有渐变波前。 与基于快照的方法相比,精确的波前扫描不会以任何方式降低吞吐量,也不需要收集器和增变器之间进行更多的通信。 它具有同等或更好的吞吐量,因为它的准确性确保它不必重复任何跟踪工作。
为什么Azul的gc没有这个问题?
他们仍然有这个问题,但他们通过实施硬件读取障碍减轻了这个问题。 之前已经提出了读取障碍,但是软件读取障碍太多地降低了吞吐量,因为指针读取比写入更为普遍。
如前所述,如果“问题”由于快照与快照行为而导致效率低下,那么C4就不具备这一function,因为它是精确的波前跟踪器。 此外,Azul的C4收集器不需要或使用硬件读取障碍,因为它运行在香草x86和Linux系统上,并且在基于快照的追踪收集器所做的硬件上实现了更好的吞吐量(参见[1]中的吞吐量比较)。 。
但是,问题中的“问题”是“为什么垃圾收集者总是停下来呢?” 波阵面的精确性(或不)在垃圾收集器中几乎没有占优势的停顿。 同时存在并且大部分是并行的(即使效率低于C4)标记确实存在,但是它们的收集器仍然暂停。 问题是追踪只是收集的一部分。 跟踪只会告诉你什么是活的,它在哪里。 它不会给你任何回忆,也不会把碎片分解。 这个问题在各种学术论文中都有深入的讨论(见C4论文参考文献[1])。
这是压缩(以及隐含的对象重新定位),似乎是目前服务器JVM上的收集器的致命弱点,以及固有的导致它们停顿的东西。 将单个对象从一个地方重新定位到另一个地方的简单行为意味着您必须在程序使用它们之前将所有引用指向该对象。 对于大多数商业运输收集器来说,这意味着停止世界的暂停,以防止应用程序在修复引用时运行。
C4利用自我修复的LVB障碍(一种新型的读取障碍,在[2]中引入并在[1]中以软件forms使用),以避免在应用程序允许运行之前修复引用。 这就是它避免了其他collections家最终不得不采取的停顿。 与以前的非自我修复障碍相比,自我修复质量将阅读障碍的dynamic成本降低了几个数量级(例如学术作品中其他并行压缩器所使用的小溪式障碍,时间collections家)。 读取屏障成本显着降低的结果是,它适用于分代代收集和服务器级JVM。
[1]:“C4:连续并发压缩收集器” http://dl.acm.org/citation.cfm?id=1993491&dl=ACM&coll=DL&CFID=85063603&CFTOKEN=84074207 [2]:“暂停GCalgorithm” http: //static.usenix.org/events/vee05/full_papers/p46-click.pdf [3]:“并行垃圾收集algorithm的正确性保持推导”www.srl.inf.ethz.ch/papers/pldi06-cgc。 PDF格式
(阿祖尔系统欧洲,中东和非洲地区技术经理Graham Thomas)
为什么垃圾收集者有一般暂停?
GC通过从一组全局根(全局variables,线程堆栈和CPU寄存器)开始追踪可达堆块来工作。 地理信息系统从快照到即时的滑动规模。 快照GC根据全局根和堆拓扑的快照工作。 随着增值器运行,即时GC逐渐更新对堆的解释。
完全快照GC获得高吞吐量,因为收集器几乎完全独立于增变器运行,但是由于拍摄快照导致暂停,所以具有高延迟。 完全即时的GC获得低延迟,因为一切都是逐步完成的,但吞吐量较低,因为增变器和GC之间的细微沟通。
实际上,所有的GC都位于这两个极端之间。 VCGC主要是一个快照GC,但它使用写屏障来保持收集器知道堆拓扑的变化。 Staccato是世界上第一个并行和并发和实时GC,但它仍然批量进行一些操作,以保持堆栈分配的效率。
为什么Azul的gc没有这个问题?
他们仍然有这个问题,但他们通过实施硬件读取障碍减轻了这个问题。 之前已经提出了读取障碍,但是软件读取障碍太多地降低了吞吐量,因为指针读取比写入更为普遍。
为什么垃圾收集器不能简单地mprotect(region_it's_working_on, PROT_READ)
并实现一个SIGSEGV
处理程序来更新所有访问对象的指针呢? 是的,你必须跟踪所有指向一个对象的指针。