Language agnostic 为什么RAII和垃圾收集是互斥的?

Language agnostic 为什么RAII和垃圾收集是互斥的?,language-agnostic,garbage-collection,raii,Language Agnostic,Garbage Collection,Raii,虽然我认为我理解了问题的要点(即一个好的GC跟踪对象,而不是范围),但我对这个主题的了解还不够,无法说服其他人 在注意到跟踪垃圾收集器是最常见的类型之后,您能解释一下为什么没有带确定性析构函数的垃圾收集语言吗?From: 不支持跟踪垃圾回收 确定性。变成 符合垃圾收集条件的将 通常最终会被清理干净,但是 无法保证何时(或甚至何时) 如果)那将会发生 因此,依赖RAII可能导致资源处置过晚 因此,例如,Java有一个“避免终结器”的准则(Josua Bloch的“有效Java”中的第6项)。“终结

虽然我认为我理解了问题的要点(即一个好的GC跟踪对象,而不是范围),但我对这个主题的了解还不够,无法说服其他人

在注意到跟踪垃圾收集器是最常见的类型之后,您能解释一下为什么没有带确定性析构函数的垃圾收集语言吗?

From:

不支持跟踪垃圾回收 确定性。变成 符合垃圾收集条件的将 通常最终会被清理干净,但是 无法保证何时(或甚至何时) 如果)那将会发生

因此,依赖RAII可能导致资源处置过晚


因此,例如,Java有一个“避免终结器”的准则(Josua Bloch的“有效Java”中的第6项)。“终结器中不应执行任何时间关键的操作。”

垃圾收集器不能一直运行(refcounting越来越近,但通常不算作垃圾收集),因此它甚至不尝试。这显然是不切实际的。因此,在对象变得不可访问(例如,因为唯一的引用超出范围)和GC收集对象(可能触发终结器)之间存在不可避免的延迟。这种延迟是不确定的。。。除非(然后,严格意义上的确定性破坏是可能的,尽管仍然不切实际)迫使GC进入确定性计划——但这非常接近“GC一直运行”,这仍然是难以置信的不切实际


因此,GC和确定性清理是互斥的,因为GC执行所有清理,它无法承担确定性的清理,但必须依赖于最大限度地提高其效率。

它们不是互斥的。可以自由使用C++与LIGBC(Boehm Reiser Detlefs收集器)。您仍然可以使用RAII、智能指针和手动删除,但在GC运行时,您也可以“忘记”删除一些对象

@Andy关于资源被处理得太晚的回答忽略了重要的一点:从语义上来说,关键不是延迟释放资源,而是释放的顺序

GC倾向于对发布进行良好排序的原因是,它需要对排序需求(依赖项)进行拓扑排序,这是一种昂贵的算法


尽管如此,ocamlgc还是有一个有趣的功能,您可以在其中将定稿器附加到对象。如果对象变得不可访问,则将运行终结器,但不会删除该对象(因为终结器可能使其再次可访问:在这种情况下,您甚至可以附加另一个终结器)。这些最终确定者可以提供一些对排序的控制。

FWIW关于垃圾收集的维基百科页面大部分是错误的,包括该部分。@JonHarrop-欢迎对这个答案的任何具体批评。很明显,简单GC算法的操作在单线程应用程序中是完全确定的。这可能不难预测,但我的系统至少有一个显式的collect()调用,它运行GC并将运行finalizers。确定性仅在多线程应用程序中丢失,这些应用程序可能具有有界或无界的非确定性(取决于系统和应用程序),因此,即使在这种情况下,GC是否会让事情变得比现在更糟还不清楚。@Yttrill:没错,但我认为根本的问题是,在垃圾收集的上下文中使用“决定论”这个词的人都不理解这个词的实际含义。-1问题是错误的。有一些垃圾收集语言具有确定性析构函数,例如.NET上的IDisposable为C#、VB.NET和F#提供确定性销毁。发布顺序可能很重要。但未定义的延迟发布,以及可能的完全失败发布,也可能很重要。不是非此即彼,而是兼而有之。释放的未定义延迟可能确实很重要,包括释放内存!业绩很重要。但它在语义上并不相关。但是,发布的完全失败确实很重要,但是如果GC在终止点运行,则不会发生这种情况。对于某些资源(如Unix上的文件句柄),用户倾向于在终止时不运行GC,因为操作系统无论如何都会释放这些资源。使用GC的一般建议是不要将RAII用于关键资源,在程序控制下发布。然而,目前还不清楚懒惰评估(如Haskell中的懒惰评估)意味着什么。