C#:按照分配的相反顺序处理资源有啥好处吗?
Posted
技术标签:
【中文标题】C#:按照分配的相反顺序处理资源有啥好处吗?【英文标题】:C#: Is there an Advantage to Disposing Resources in Reverse Order of their Allocation?C#:按照分配的相反顺序处理资源有什么好处吗? 【发布时间】:2010-12-14 18:19:54 【问题描述】:许多年前,我被告诫要尽可能以与分配方式相反的顺序释放资源。那就是:
block1 = malloc( ... );
block2 = malloc( ... );
... do stuff ...
free( block2 );
free( block1 );
我想在 640K MS-DOS 机器上,这可以最大限度地减少堆碎片。在 C# /.NET 应用程序中执行此操作有什么实际优势,还是这种习惯已经过时了?
【问题讨论】:
【参考方案1】:“运行时不保证调用 Finalize 方法的顺序。例如,假设有一个对象包含指向内部对象的指针。垃圾收集器检测到这两个对象都是垃圾。再者说先调用内部对象的Finalize方法,现在允许外部对象的Finalize方法访问内部对象并调用内部对象的方法,但是内部对象已经终结,结果可能无法预料。因此,强烈建议 Finalize 方法不要访问任何内部成员对象。"
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
因此,您可以随心所欲地担心您的 LIFO 处置语义,但如果您泄露了一个,Dispose() 将按照 CLR 所希望的任何顺序被调用。
(这或多或少是上面威尔所说的)
【讨论】:
【参考方案2】:如果您指的是对象上的析构函数被调用的时间,那就是垃圾收集器,编程对此几乎没有影响,而且根据语言定义,它是明确的非确定性的。
如果您指的是调用 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.
【讨论】:
【参考方案3】:如果你的资源创建得很好,这应该没关系(很多)。
但是,许多创建不佳的库没有进行适当的检查。以与分配相反的方式处置资源通常意味着您首先处置依赖于其他资源的资源 - 这可以防止编写不佳的库引起问题。 (在这种情况下,您永远不会处置资源,然后使用取决于第一个资源的存在。)
这也是一种很好的做法,因为您不会意外地过早地释放其他对象所需的资源。
这里有一个例子:看一个数据库操作。您不想在关闭/处置您的命令(使用连接)之前关闭/处置您的连接。
【讨论】:
创作好不好。它必须依赖于订单,依赖于发布,并且在许多情况下都是已知的。在数据库、事务和任何在堆栈上运行的东西(大多数软件)的所有实现中,这都没有什么关系。锁是另一个例子,有大量非外部和非穷人的库使用它。文件操作和它们的锁是另一个。事件泄漏另一个。任何依赖于另一个的非托管资源。创造与毁灭齐头并进,不能断断续续地把成语理解为Resource-Initialization-Is-“well-Creation”。 因此,RIIWC 矛盾修饰语中的 WC 被替换为 Aquisition,这意味着 Release btw。而且由于内存和大量资源大多是抽象的,操作,想法就出现了……各种黑客攻击接踵而至。简而言之,这只是问题的本质,而且很重要。 虽然我不是在这里捍卫顺序依赖,但正确的观察是它非常相关但很少需要。但这甚至是 VM 的官方规范也受到极大限制。尤其是 Java impl 和 CLR 在较小但仍然很重要的程度上。不破坏大量工作代码和所做的假设是一种技巧,这是编译器和 jit 后端设计人员有意识的决定。能够进行与订单无关的处理的代码有很多可能性,但在很多情况下可能是不可行的。【参考方案4】:嵌套的“使用”向您显示“已过时”并没有真正启用,而且很少启用(在 40 年的证据之后不要说永远不会)。这包括在 CMOS 上运行的基于堆栈的 VM。
[ 尽管 MSDN.com 和 Duffius 进行了一些尝试使其消失,但您知道为您管理堆和堆栈之间的区别。多么聪明的主意……在太空中]
【讨论】:
【参考方案5】:不要打扰。 GarbageCollector 保留对堆上的对象进行碎片整理和移动的权利,因此不知道事物的顺序。
此外,如果您要处理 A 和 B 并且 A 引用 B,那么在处理 A 时 A 是否处理 B 无关紧要,因为 Dispose 方法应该可以多次调用而不会引发异常。
【讨论】:
是的,前提是您不会意外使用“已处置”引用(通过从它创建的另一个对象),因为您以任意顺序处置。以上是关于C#:按照分配的相反顺序处理资源有啥好处吗?的主要内容,如果未能解决你的问题,请参考以下文章
基于提示的 Oracle SQL 调优——对最近的版本有啥好处?