为什么 RAII 和垃圾收集是相互排斥的?
虽然我认为我理解问题的要点(即一个好的 GC 跟踪对象,而不是范围),但我对这个主题的了解还不足以说服其他人。
您能给我解释一下为什么没有带有确定性析构函数的垃圾收集语言吗?
While I think I understand the gist of the problem (i.e. a good GC tracks objects, not scope), I don't know enough about the subject to convince others.
Can you give me an explanation on why there are no garbage-collected languages with deterministic destructors?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
它们并不相互排斥。请随意将 C++ 与 libgc(Boehm-Reiser-Detlefs 收集器)一起使用。您仍然可以使用 RAII、智能指针和手动删除,但随着 GC 的运行,您也可能“忘记”删除某些对象。
@Andy 关于资源处置得太晚的回答忽略了重要的一点:语义上至关重要的不是延迟释放资源,而是释放的顺序。
GC 往往不能很好地对释放进行排序的原因是,它需要对排序要求(依赖项)进行拓扑排序,而这是一种昂贵的算法。
尽管如此,Ocaml GC 有一个有趣的功能,您可以将终结器附加到对象。如果该对象变得不可访问,则终结器将运行,但该对象不会被删除(因为终结器可以使其再次可访问:在这种情况下,您甚至可以附加另一个终结器)。这些终结器可以提供对排序的一些控制。
They are NOT mutually exclusive. Feel free to use C++ with libgc (Boehm-Reiser-Detlefs collector). You can still use RAII, smart pointers, and manual deletion, but with the GC running you can also just "forget" to delete some objects.
@Andy's answer regarding resources being disposed too late misses the important point: it isn't the delay releasing resources which is crucial semantically, but rather the order of release.
The reason GC tends not to order release well is that it would require a topological sort on ordering requirements (dependencies) and that's an expensive algorithm.
Nevertheless Ocaml GC has an interesting facility where you can attach a finaliser to an object. If the object becomes unreachable the finaliser is run, however the object is not deleted (because the finaliser could make it reachable again: in that case you can even attach another finaliser). These finalisers can provide some control over ordering.
来自 Wikipedia,在注意到跟踪垃圾收集器是最常见的类型之后:
因此,依赖 RAII 可能会导致资源处置得太晚。
因此,例如,Java 有一个“避免终结器”的指南(Josua Bloch 的“Effective Java”中的第 6 条)。 “任何对时间要求严格的事情都不应该在终结器中完成。”
From Wikipedia, after noting that tracing garbage collectors are the most common type:
Therefore, relying on RAII could lead to the resource being disposed of too late.
As a result, for example, Java has a guideline to "avoid finalizers" (Item 6 in "Effective Java" by Josua Bloch). "Nothing time-critical should ever be done in a finalizer."
垃圾收集器不能一直运行(引用计数越来越接近,但通常不算作垃圾收集),因此它甚至不会尝试。这显然是不切实际的。因此,在对象变得不可访问(例如,因为唯一的引用超出范围)和 GC 收集它(可能会触发终结器)之间存在不可避免的延迟。这种延迟不是确定性的......除非(然后,严格意义上的确定性破坏是可能的,尽管仍然不切实际)迫使 GC 进入确定性计划 - 但这非常接近“GC 一直运行” ,这仍然非常不切实际。
因此,GC 和确定性清理是相互排斥的,因为 GC 会完成所有清理工作,但它无法承担确定性清理任务,而必须依赖于最大化其效率。
The garbage collector can't run all the time (refcounting gets closer, but generally doesn't count as garbage collection), so it doesn't even try. It's plain impractical. Therefore, there is an inevitable delay between an object becoming unreachable (e.g. because the only reference goes out of scope) and the GC collecting it, possibly firing a finalizer. This delay is not deterministic... unless (and then, deterministic destruction in the strictest sense of the word is possible, although still impractical) force the GC into a deterministic schedule - but this gets pretty close to "GC running all the time", which is still incredibly impractical.
So GC and deterministic cleanup are mutually exclusive because the GC does all the cleanup and it cannot afford do be deterministic but must rely on maximizing its efficiency.