手动调用 `gc()`,是否会立即执行所有 `finalizer`?

7

我有一些代码怀疑会出现内存泄漏。由于代码使用了 ccall 并且在指针中维护了重要信息,这些指针应该在 finalizer 调用的代码中被释放。

在我的调试中,我正在调用 gc()。我想知道是否这会立即触发所有已经移出作用域的对象所附加的 finalizer

答案仅与 julie 0.5+ 相关。

1个回答

8
在 @Isaiah 的回答讨论(已删除)之后,我联系了一些内部人员,并就此事进行了澄清。结果,我可以很有把握地告诉您,当在顶层(即不在本地范围内)调用 gc() 时,可以依靠以下保证:
如果一个对象不可到达并且您调用 gc(),它将被终结。
这是非常明确的。顶层部分很重要,因为当在本地范围内调用 gc() 时,局部引用可能会或可能不会被认为是可达的,即使它们永远不会再次使用。
这个保证消除了一些关于“可达性”的不确定性,因为语言运行时可能出于各种原因保留对某些对象的引用。这些原因应该被全面地记录下来,但目前尚未这样做。运行时保留对象的几个值得注意的情况包括:
单例类型的唯一实例是永久的,永远不会被收集或终结;
方法缓存也是永久的,特别是这意味着当您可能期望它们被释放时,模块不会被释放,因为方法缓存保留对定义它们的模块的引用。
然而,在“正常情况”下,也就是我认为这个问题正在解决的情况下,是的,当一个对象不再可达时调用 gc() 将会在返回 gc() 调用之前“立即”收集和终结它。

这是一个很好的回答,Stefan。可以说这只适用于当前的gc()实现,而不是语言契约吗?也就是说,这种行为在未来可能会发生变化。例如,如果我们获得了多线程gc,那么情况可能会改变。 - aviks
是的,如果我们得到了一个并发的垃圾回收,那么一切都不确定了 - 但我们当然必须考虑其影响。在并发垃圾回收中,有mutator线程和collector线程同时运行,因此甚至不清楚在mutator线程中调用gc()是什么意思。它可能被安排为阻塞调用它的mutator线程,直到collector线程中发生“完整收集”。或者它可以在并发收集器的位置上调用停止-世界GC算法,但这样我们就有了两个不同的GC实现,这将很奇怪。 - StefanKarpinski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接