垃圾收集中的疏散和压实之间的根本区别是什么?

时间:2013-12-29 20:37:00

标签: java garbage-collection

我已经阅读了大量有关Java SE 6和7的HotSpot GC的文档。在讨论获取可用内存的连续区域的策略时,提出了两种“竞争”方法:疏散方法(通常应用于年轻的gen),其中活动对象从'from'复制到空'to'和Compaction(CMS的后退),其中活动对象被移动到碎片区域内的一侧以形成连续的块使用了未使用的内存。

这两种方法都与“实时集”的大小成正比。不同之处在于疏散需要x2倍的空间,而实际集合则不需要压缩。

为什么我们需要撤离技术呢?需要完成的复制量是相同的,但需要预留更多的堆大小,并且不允许更快的重新映射参考文献。

正确:疏散可以并行执行(其中 - 压缩不能,或者至少不那么容易)但是这个特性从未被提及过,并且看起来并不那么重要(考虑到重新映射比移动要贵得多)。 / p>

2 个答案:

答案 0 :(得分:4)

一个大问题是,在“撤离”时,腾出的空间实际上是空的,而在“压实”时,一些其他物体Y可能被移动到物体X所在的空间中。这使得纠正指针变得更加困难,因为人们不能简单地使用指针指向无效位置的事实来提示需要更新的代码。并且无法将“转发指针”存储在“无效”位置。

这使得GC更少并发 - 应用程序必须处于“GC冻结”较长时间。

答案 1 :(得分:1)

紧凑性更适用于可回收对象的数量较少的情况(例如,终身生成),因为经过几次GC循环后,寿命长的对象往往会占据堆的下部,因此所需的工作较少由收集者来完成。如果在这种情况下使用复制收集器,则该收集器的性能将非常差,因为前一个循环中几乎相同的存活对象将需要一次又一次地从一个位置复制到另一个位置。

当可回收对象的数量非常多(例如,年轻代)时,复制是适合的,因为需要复制的幸存对象很少。在这种情况下,使用压缩可能会导致性能下降,因为尚存的对象可能会分散在整个堆中。

除了@Hot Licks回答中提到的以外,复制收集器允许我们存储转发指针,以防止在同一“来自”空间中的另一个对象引用已经移动的对象时进入无限循环。

此外,只有在识别出所有活动对象后才可以开始压缩,但是一旦识别出活动对象(使用多个线程),就可以将其复制到新位置。