许多年前,我曾被告诫,尽可能以相反的顺序释放资源以分配资源。那就是:
block1 = malloc( ... );
block2 = malloc( ... );
... do stuff ...
free( block2 );
free( block1 );
我想象在640K MS-DOS机器上,这可以最小化堆碎片。在C#/ .NET应用程序中执行此操作是否有任何实际优势,或者这种习惯是否已经超过其相关性?
答案 0 :(得分:5)
如果您的资源创建得很好,这应该不重要(很多)。
然而,许多创建不良的库没有进行适当的检查。以与其分配相反的方式处置资源通常意味着您首先处理依赖于其他资源的资源 - 这可以防止写得不好的库导致问题。 (你永远不会丢弃一个资源,然后使用一个依赖于第一个存在的资源。)
这也是一种很好的做法,因为你不会过早意外地处理某些其他对象所需的资源。
这是一个例子:查看数据库操作。在关闭/处理命令(使用连接)之前,您不希望关闭/处置连接。
答案 1 :(得分:4)
不要打扰。 GarbageCollector保留对堆上的对象进行碎片整理和移动的权利,因此无法确定事物的顺序。
此外,如果你处理A和B以及A引用B,当你处理A时,A处理B应该无关紧要,因为Dispose方法应该可以多次调用而不会抛出异常。
答案 2 :(得分:1)
如果你指的是调用对象上的析构函数的时间,那么这就是垃圾收集器,编程对它的影响很小,根据语言定义它是明确的非确定性的。
如果您指的是调用IDisposable.Dispose(),那么这取决于实现IDisposable接口的对象的行为。
通常,对于大多数Framework对象,顺序无关紧要,除非它对调用代码很重要。但是如果对象A维持对对象B的依赖,并且对象B被处理掉,那么对象A的某些事情就很重要。
在大多数情况下,Dispose()不是直接调用的,而是作为using或foreach语句的一部分隐式调用,在这种情况下,根据语句嵌入,逆序模式自然会出现。
using(Foo foo = new Foo())
using(FooDoodler fooDoodler = new FooDoodler(foo))
{
// do stuff
// ...
// fooDoodler automatically gets disposed before foo at the end of the using statement.
}
答案 3 :(得分:0)
嵌套'使用'显示'过时'并不是真正开启的,很少是(在40年的证据之后永远不会去说)。这包括基于堆栈的运行在CMOS上的虚拟机。
[尽管MSDN.com和Duffius试图让它消失,但你知道管理堆栈和堆栈之间的差异。多么聪明的想法......在太空中]
答案 4 :(得分:0)
“运行时不会对调用Finalize方法的顺序提供任何保证。例如,假设有一个对象包含指向内部对象的指针。垃圾收集器检测到两个对象都是另外,假设首先调用内部对象的Finalize方法。现在,允许外部对象的Finalize方法访问内部对象并在其上调用方法,但内部对象已经完成,结果可能无法预测。这个原因,强烈建议Finalize方法不要访问任何内部的成员对象。“
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
所以你可以随心所欲地担心你的LIFO处理语义,但是如果你泄漏了一个,那么Dispose()将按照CLR所想的任何顺序被调用。
(这或多或少会说,上面说)