2011-01-12 33 views
5

尽管我认为我理解问题的要点(即一个好的GC跟踪对象,而不是范围),但我不太了解该主题以说服其他人。为什么RAII和垃圾收集相互排斥?

你可以给我一个解释,为什么没有垃圾收集语言与确定性的析构函数?

+0

-1问题是错误的。有确定性析构函数的垃圾收集语言,例如.NET上的“IDisposable”为C#,VB.NET和F#提供了确定性的破坏。 – 2012-06-19 20:06:00

回答

3

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

@ Andy对于资源处理得太晚的回答忽略了一个重要的观点:它不是延迟释放在语义上至关重要的资源,而是释放的顺序。

GC倾向于不顺序释放的原因是它需要对排序要求(依赖性)进行拓扑排序,这是一个昂贵的算法。

尽管Ocaml GC有一个有趣的设施,您可以在其中附加一个终结器到一个对象。如果对象变得无法访问,则终结器将运行,但是该对象不会被删除(因为终结器可以使其再次可达:在这种情况下,您甚至可以连接另一个终结器)。这些终结者可以提供对订购的一些控制。

0

Wikipedia指出,追查垃圾收集器是最常见的类型后:

追踪垃圾回收不确定性 。一个对象变成 有资格进行垃圾回收,最终通常会清理掉 ,但是 没有保证的时候(或者甚至是 if)会发生。

因此,依靠RAII可能会导致资源被处置得太晚。因此,例如,Java有一个“避免终结器”(Josua Bloch的“Effective Java”中的第6项)的指导原则。 “终结者永远不应该做任何时间批判。”

+0

FWIW关于垃圾收集的维基百科页面大多是错误的,包括该部分。 – 2012-02-05 09:34:27

+0

@JonHarrop - 对这个答案的任何具体批评都欢迎。 – 2016-04-18 02:39:51

0

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

因此,GC和确定性清理是相互排斥的,因为GC执行所有清理并且无法承担确定性,但必须依靠最大化其效率。