5

许多年前,我被告诫要尽可能以与分配方式相反的顺序释放资源。那是:

block1 = malloc( ... );
block2 = malloc( ... );

... do stuff ...

free( block2 );
free( block1 );

我想在 640K MS-DOS 机器上,这可以最大限度地减少堆碎片。在 C# /.NET 应用程序中执行此操作有什么实际优势,或者这是一种已经过时的习惯?

4

5 回答 5

5

如果您的资源创建得很好,这应该无关紧要(很多)。

但是,许多创建不佳的库没有进行适当的检查。以与分配相反的方式处置资源通常意味着您首先处置依赖于其他资源的资源 - 这可以防止编写不佳的库引起问题。(在这种情况下,您永远不会处置资源,然后使用取决于第一个资源的资源。)

这也是一种很好的做法,因为您不会意外地过早地处置其他对象所需的资源。

这是一个示例:查看数据库操作。您不想在关闭/处置您的命令(使用连接)之前关闭/处置您的连接。

于 2009-11-09T19:37:24.667 回答
4

不要打扰。GarbageCollector 保留对堆上的对象进行碎片整理和移动的权利,因此不知道事物的顺序。

此外,如果您要处置 A 和 B 以及 A 引用 B,那么在处置 A 时 A 是否处置 B 无关紧要,因为 Dispose 方法应该可以多次调用而不会引发异常。

于 2009-11-09T19:36:41.993 回答
1

如果您指的是对象上的析构函数被调用的时间,那么这就是垃圾收集器,编程对此影响很小,并且根据语言定义它是明确的非确定性的。

如果您指的是调用 IDisposable.Dispose(),那么这取决于实现 IDisposable 接口的对象的行为。

一般来说,顺序对于大多数框架对象都无关紧要,除非它对调用代码很重要。但是,如果对象 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.
}
于 2009-11-09T19:42:16.693 回答
0

嵌套的“使用”向您展示了“长寿”并没有真正开启,而且很少有(在 40 年的证据之后不要去说永远不会)。这包括在 CMOS 上运行的基于堆栈的 VM。

[ 尽管 MSDN.com 和 Duffius 进行了一些尝试使其消失,但您知道为您管理堆和堆栈之间的区别。多么聪明的主意……在太空中]

于 2009-11-09T19:36:56.833 回答
0

“运行时不保证调用 Finalize 方法的顺序。例如,假设有一个对象包含指向内部对象的指针。垃圾收集器检测到这两个对象都是垃圾。此外,假设先调用了内部对象的Finalize方法,现在允许外部对象的Finalize方法访问内部对象并对其调用方法,但是内部对象已经终结,结果可能无法预料。因此,强烈建议 Finalize 方法不要访问任何内部成员对象。”

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

因此,您可以随心所欲地担心您的 LIFO 处置语义,但如果您泄漏了一个,Dispose() 将按照 CLR 所希望的任何顺序被调用。

(这或多或少是上面威尔所说的)

于 2010-02-08T00:47:34.390 回答