OCaml GC如何确定次要堆中的哪个块是否存在

时间:2014-06-16 12:33:40

标签: garbage-collection ocaml

Chapter 21, Real World OCaml,它说:

  

次要堆是大多数短期值所在的位置。它   由一个连续的虚拟内存块组成,包含一个   OCaml块的序列。如果有空间,则分配新块   快速,恒定时间的操作,只需要几个CPU   指令。

     

为了垃圾收集次要堆,OCaml使用复制集合将次要堆中的所有活动块移动到主堆。这需要   工作与次要堆中的活动块数量成正比,   根据世代假设,这通常很小。该   次要集合阻止了世界(它停止了应用程序)   当它运行时,这就是它如此重要以至于快速完成的原因   让应用程序以最小的中断恢复运行。

我理解,正如它清楚地说,在小堆中,实时内存会转到主堆。

但是,gc如何决定次要堆中的实时内存?

是否与主要堆相同的标记和扫描进程?

基本上,在gc for major 堆期间,它会在堆栈中启动一些根,并且可以访问任何内容。

如果次要的gc也是这种情况,OCaml如何快速知道哪些根导致较小的堆内存,或者很快知道哪些根导致主要内存?


我的困惑实际上是,如果OCaml对未成年人进行相同的gc操作,那么OCaml如何区分?如果它都是从堆栈开始的,那么GC如何只收集未成年人,而不涉及主要?


修改

让我们假设次要堆大小只有4KB。这是一些代码:

let f = 
  let a1 = Array.make (4 * 1024) 1 in
  let a2 = Array.make (4 * 1024) 2 in
  let a3 = Array.make (4 * 1024) 3 in
  ...

在上面的代码中

  1. a1的地址将被置于堆栈中,真正的数组将位于次要堆中。堆栈看起来像[a1]
  2. 正在创建
  3. a2。它发现小堆已经满了,所以它会做很小的gc。 gc看看堆栈,所以在a1之后判断a1是否存在,然后a1's array将被复制到主堆,而a1的指针被改为主要的新地址?堆栈现在看起来像[a2;a1]
  4. 正在创建
  5. a3。就像2,它必须做一个小gc。请问gc是否同时通过a2和a1?特别是a1,即使a1是主要的?

1 个答案:

答案 0 :(得分:2)

从主堆到次要堆的指针相对较少,因为主堆中的值较旧。如果OCaml纯粹是功能性的,那么就不会有从主要堆到次要堆的任何指针。

实际上OCaml不是纯粹的功能,并且可以使用指向较小堆中的新值的指针来更新主堆中的旧值。任何此类写操作都会通过写入障碍,从下一个次要堆集合的角度将主要堆值记录为根。不需要扫描主要堆的其余部分以进行次要集合。

前进到the book your are currently reading中的“代际指针”部分,以快速了解写屏障实现。

关于你的例子:

是的,GC访问堆栈以确定必须保留哪些次要堆值,但是在第3点,当GC看到堆栈中指向a1的指针指向次要堆之外时,它可以忽略它并立即继续a2。从主要堆到次要堆的所有引用都已由写入障碍收集在引用表中。不需要访问主堆中的其他位置,甚至不需要访问堆栈中引用的位置。

  

gc会同时通过a2和a1吗?

不,只有a2。没有理由访问a1因为它在次要堆之外,因此不能指向次要堆,除非它已被修改,在这种情况下它将在引用表中单独注册。