如何使用 Boehm GC 实现弱引用?

How does one implement weak references with Boehm GC?

我有一个使用 Boehm GC 实现的个人项目。我需要实现一种事件类型,它应该包含对其他事件的引用。但我还需要确保指向的事件仍然是可收集的,因此我需要弱引用。

假设我们有事件 A、B 和 C。我将这些事件配置为在其中任何一个发出信号时向事件 X 发出信号。这意味着 A、B 和 C 必须持有对事件 X 的引用。我想要的是,如果事件 X 不可到达,则事件 A、B 和 C 不再需要发出信号。于是想到了弱引用

还有其他方法吗?我不想更改 GC,但如果有必要(分配界面保持干净)我可以。

该项目是用C语言编写的,如果需要,我会提供更多信息。值得注意的是,如果有任何方法可以直接使用这种语义来实现此类事件,则不需要实际的弱引用(事件可能有一个引用循环,尽管它们没有发出信号)。

Boehm GC 本身没有弱引用的概念。但是,它不会扫描系统 malloc 分配的内存以查找对托管对象的引用,因此存储在此类内存中的指针不会阻止收集指向的对象。当然,这种做法意味着包含指针的对象不会被收集器管理。

或者,应该可以滥用 GC_MALLOC_ATOMIC()GC_malloc_explicitly_typed() 来获取一个托管对象,该对象可以包含指向其他托管对象的指针,而不会阻止收集其他对象。这基本上涉及向 GC 撒谎某些成员是否是指针,以防止它们被扫描。

无论哪种方式,您还需要某种机制来在收集弱引用对象时接收通知,以避免之后尝试访问它们。 GC 有一个接口,用于注册 finalizer 回调,以便在收集对象之前调用,这看起来是您最好的选择。

总的来说,我认为你要求的是可行的,但涉及很多 DIY。在高层次上,

  • 使用GC_MALLOC_ATOMIC()围绕指向弱引用对象的指针分配包装器对象。以这种方式分配它允许包装器本身由 GC 管理,而无需在 GC 的可达性分析期间扫描内部指针。
  • 使用 GC_register_finalizer 注册一个终结器函数,当 GC 决定指向的对象不可访问时,将包装器的指针设置为 NULL
  • 包装器的用户有义务在尝试取消引用之前检查其中的指针是否 NULL