tenured Ron.Zheng(郑云红)
Parallel Scavenge(并行回收)
本文我们将会描述并行垃圾回收(Parallel GC)是如何工作的。具体来说,这是一个在Eden空间运行Parallel Scavenge收集器、在老年代(Tenured generation)空间运行并行标记(Parallel Mark)和Sweep收集器的组合。你可以通过传入参数’ -XX:+UseParallelOldGC’来获取这些特性,虽然在某些机器类型上它事儿默认的。
如果你对垃圾收集器的内容还没有一个总体的了解,你可以先阅读关于垃圾回收的第一篇文章。
Eden and Survivor空间
在并行回收收集器中,eden和survivor空间的回收是使用大家所熟知的Hemispheric GC方法。对象初始分配存储到Eden空间,一旦Eden空间不足,Eden空间的垃圾回收(gc)将会被触发。垃圾回收时识别可达的对象并复制这些可达对象到活跃的survivor空间。然后将整个Eden空间视为一个空闲的、连续的、可以重新分配的内存块。tenured
在这种情况下的分配过程就像切一块奶酪一样。每一块都会被连续的切下来,然后旁边被切下来的这些切片就会被“吃掉”,优势在于分配仅仅只需要指针相加。
为了识别可达的对象就要进行对象图的检索。检索从一组确保可达的“root”对象开始,例如每个线程都有一个root对象。然后搜索找到root集所指向的对象,然后不停的向外拓展直到找到所有的可达对象。下图很好的展示了这一过程。
并行回收(parallel scavenge)上下文中的并行(Parallel )所指的是同时运行多个线程来完成垃圾回收。千万不要和增量式GC(incremental GC)相混淆,即收集器可以和应用程序同时或者交叉运行。并行回收通过更好地使用现代多核CPU来提高总体GC吞吐量。并行特性是通过给每个线程一组root标记和对象表的一部分来实现。
有两个幸存者空间(survivor spaces),但是其中只有一个在任何时候都是处于激活状态。它们回收垃圾的方式和eden空间的回收方式一致。主要思想就是当对象从eden空间中升迁(eden空间进行垃圾回收时幸存下来的对象)时这些对象将会被拷贝到活跃的幸存者空间(survivor space)中。然后,当撤销空间的时候它们就会被拷贝到不活跃的幸存者空间(survivor space)中。一旦活跃的幸存者空间(survivor space)完成撤销,不活跃的幸存者空间(survivor space)立马被激活并且被撤销的活跃空间变成不活跃。这主要是通过将指针指向幸存者空间(survivor space)的开头来实现的,并且意味着幸存者空间(survivor space)中的所有不可达对象可以以分配给单个指针为代价而被释放。
新生代的设计与时间权衡(Young Gen design and time tradeoffs)
因为只是涉及到拷贝可达对象和实时变换指针,所以eden空间和幸存者空间(survivor space)的回收和可达对象的数量成正比。这一点非常重要,因为由于分代假设(generational hypothesis)我们知道大多数的对象在很早的时候就已经不可达,并且没有GC成本来释放与之相关的内存。
最终,eden空间被组织成一个单独连续的空间,使得对象分配的开销变得很低。C程序可能会使用“malloc”命令分配内存块,这将会涉及到遍历一些列空闲的内存空间尝试找到足够大的内存块。当你使用arena allocator并分配你需要的连续空间时,你需要做的就是检查是否有足够的空闲空间然后以对象的大小为增量来移动指针。
细腻温柔