想象一下,我有一个名为libcat的C库,用于与蓬松的猫互动。因此,我正在为OCaml编写绑定(bind),以简化与蓬松的交互。

module type CAT = sig
   type cat
   val find : ... -> cat
   val feed : cat -> unit
   ...
end ;;
module Cat : CAT = ...

libcat中已经内置了相当多的内存管理功能,例如缓存,释放损坏的玩具,甚至可能是用于清空垃圾的有限范围的垃圾收集器。但是,总体而言,libcat要求用户明确释放未使用的资源,例如丢失的玩具。

我为Cat.find编写了一个C stub ,它使用libcat的cat_find例程查找并分配了cat,但随后将指向cat的结果指针存储在使用caml_alloc_custom创建的自定义块中。

我已经在传递给caml_alloc_custom的custom_operations结构中添加了一个finalize方法。至关重要的是,我已经使这种finalize方法释放了这只猫,因为我在回答电话异常时讨厌猫在门上抓挠。

我现在担心的是,如果OCaml曾经复制过Cat.cat类型的自定义块,那么OCaml的垃圾收集器可能会在我们仍在播放时释放蓬松的东西。例如 :
let fluffy = Cat.find ;;
fluffy.yodel ;;
let meow = fluffy ;;
...
meow.feed ;;

我们必须假设...将在最后一次显式引用蓬松之后(例如打破盘子)触发OCaML的垃圾收集器。这个垃圾回收事件会调用fluffy的finalize方法并释放她吗?还是喵会简单地引用蓬松的原始自定义块,从而防止蓬松被释放?

我以为蓬松在这种情况下无法释放,否则OCaml肯定会在custom_operations结构中要求重复的方法,但我觉得最好问一下。如果实际上可以将蓬松的东西释放,我是否可以通过仅让OCaml通过引用处理她来防止这种情况?大致 :
  type cat_name = real_cat ref
  type real_cat

最佳答案

自定义块本身(即从caml_alloc_custom获得的字节)是Caml堆的一部分,可以像其他任何对象一样进行移动。¹自定义块包含指向也可由C²代码访问的数据结构的指针是很常见的住在 Camel 堆外面; Caml将自定义块的内容视为不透明,甚至不知道它是否包含指针,因此不会接触这些数据结构。

当您编写let meow = fluffy时,不会进行任何复制:您只是给同一个对象起一个新名称。 Caml绝不会复制自定义块;如果需要,您必须在库中提供copy_cat原语。

¹
实际上,只有次要的垃圾收集器和压缩器会实际移动块,而主要的gc不会。但这不是您应该依靠的东西。

²
或Fortran,或您的程序或库使用的任何其他语言。

10-06 05:53