一尘不染

堆压缩如何快速工作?

algorithm

他们说,压缩垃圾收集器比传统的内存管理要快,因为它们只需要收集活动对象,并且通过将它们重新排列在内存中,以便所有内容都在一个连续的块中,最终不会造成堆碎片。但是,如何快速完成呢?在我看来,这相当于bin-
packing问题,这是NP难题,在我们对计算知识的当前限制内,无法在合理的时间内在大型数据集上完成。我想念什么?


阅读 315

收藏
2020-07-28

共1个答案

一尘不染

压缩意味着在RAM中移动对象,以便删除一些对象(死掉的对象,应该回收GC),而所有剩余的对象在RAM中变得连续。

大多数压缩GC通过在从操作系统获得的 单个
连续区域内分配对象来工作。然后,压实就像清除死掉的物体,然后将所有剩余的活动物体“向左”推挤,挤出孔洞。如果GC通过压缩进行工作,则分配仅是将“分配区域的末端”指针向上移动的问题。综合而言,在分配区域中,存在一个指针,以便空闲区域由该指针之后的字节组成。要为对象分配空间,只需将指针向上移动新对象大小即可。有时,GC决定运行时间了,检测到死对象,将孔挤出,从而降低了分配指针。

压缩GC的性能提高来自以下几个方面:

  • 进行分配时,无需找到合适的“孔”:通过构造,自由空间始终是单个大区域,只需向上移动指针就足够了。
  • 没有碎片:压缩将所有活动对象移动到一起,但是这可以看作是将所有 一起移动到一个大的自由空间中。
  • 地方性得到改善。通过将活动对象移动到相邻区域,可以改善有关缓存的行为。特别是,压缩算法倾向于将对象保持在它们各自的分配顺序中(对象被滑动但不交换),据报道,对于大多数应用程序来说,这在启发式上是好的。

如果
操作系统拒绝提供单个分配区域,而是产生多个块,那么事情会变得更加复杂,并且可能开始看起来像装箱问题,因为压缩GC必须决定每个块在哪个块中去。活物。但是,装箱的复杂性在于通常情况下找到“完美”的匹配。对于内存分配器而言,一个近似的解决方案已经足够了。

压缩算法的算法困难在于更新所有指针,以便它们指向新的对象位置。通过严格的键入,.NET虚拟机可以明确确定RAM中的每个字是否都是指针,但是在不使用过多额外RAM的情况下有效地更新所有指针可能很棘手。HBM
Jonkers在“快速垃圾压缩算法”(《信息处理快报》,第9卷,第1期,1979年,第26-30页)中描述了一种非常巧妙的算法。我在Vast
Internet上找不到该论文的副本,但是该算法在“垃圾回收”中进行了描述琼斯和林斯的著作(第5.6节)。我热烈地向有兴趣了解垃圾收集器的任何人推荐这本书。Jonkers的算法需要在活动对象上进行两次线性遍历,并且易于实现(几十行代码,仅此而已;最困难的部分是理解其工作原理)。

世代相传的收藏家
带来了更多的复杂性,他们通常在大多数情况下尽量不影响大多数物体,而只优先使用年轻物体。在这里,这意味着只压缩堆的末端;完全压缩的应用很少。这里的重点是,尽管完全压缩,尽管是线性的,但仍可能引起明显的停顿。分代GC试图使这种暂停变得罕见。再有,琼斯和林斯的书是必读的。

2020-07-28