简体   繁体   English

C#:以分配的逆序排列资源是否有优势?

[英]C#: Is there an Advantage to Disposing Resources in Reverse Order of their Allocation?

Many years ago, I was admonished to, whenever possible, release resources in reverse order to how they were allocated. 许多年前,我被告诫,尽可能以相反的顺序释放资源以分配资源。 That is: 那是:

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

... do stuff ...

free( block2 );
free( block1 );

I imagine on a 640K MS-DOS machine, this could minimize heap fragmentation. 我想在640K MS-DOS机器上,这可以最小化堆碎片。 Is there any practical advantage to doing this in a C# /.NET application, or is this a habit that has outlived its relevance? 在C#/ .NET应用程序中执行此操作是否有任何实际优势,或者这种习惯是否已经超过其相关性?

If your resources are created well, this shouldn't matter (much). 如果您的资源创建得很好,这应该不重要(很多)。

However, many poorly created libraries don't do proper checking. 但是,许多创建不良的库不能进行适当的检查。 Disposing of resources in reverse of their allocation typically means that you're disposing of resource dependent on other resources first - which can prevent poorly written libraries from causing problems. 以与其分配相反的方式处置资源通常意味着您首先处理依赖于其他资源的资源 - 这可以防止写得不好的库导致问题。 (You never dispose of a resource, then use one that's depending on the first's existence in this case.) (你永远不会丢弃一个资源,然后在这种情况下使用一个依赖于第一个资源的资源。)

It also is good practice, since you're not going to accidentally dispose a resource required by some other object too early. 这也是一种很好的做法,因为你不会过早意外地处理某些其他对象所需的资源。

Here's an example: look at a database operation. 这是一个例子:查看数据库操作。 You don't want to close/dispose your connection before closing/disposing your command (which uses the connection). 在关闭/处理命令(使用连接)之前,您不希望关闭/处置连接。

Don't bother. 不要打扰。 The GarbageCollector reserves the right to defragment and move objects on the heap, so there's no telling what order things are in. GarbageCollector保留对堆上的对象进行碎片整理和移动的权利,因此无法确定内容的顺序。

In addition, if you're disposing A and B and A references B it shouldn't matter if A disposes B when you dispose A, since the Dispose method should be callable more than once without an exception being thrown. 另外,如果你处理A和B以及A引用B,当你处理A时,A处理B应该无关紧要,因为Dispose方法应该可以多次调用而不会抛出异常。

If you are referring to the time the destructor on the objects gets called, then that's up the garbage collector, the programming can have very little influence over that, and it is explicity non-deterministic according to the language definition. 如果你指的是对象上的析构函数被调用的时间,那么这就是垃圾收集器,编程对它的影响很小,根据语言定义它是明确的非确定性的。

If you are referring to calling IDisposable.Dispose(), then that depends on the behavior of the objects that implement the IDisposable interface. 如果您指的是调用IDisposable.Dispose(),那么这取决于实现IDisposable接口的对象的行为。

In general, the order doesn't matter for most Framework objects, except to the extent that it matters to the calling code. 通常,对于大多数Framework对象,顺序无关紧要,除非它对调用代码很重要。 But if object A maintains a dependency on object B, and object B is disposed, then it could very well be important not to do certain things with object A. 但是如果对象A维持对对象B的依赖,并且对象B被处理掉,那么对于对象A做某些事情是非常重要的。

In most cases, Dispose() is not called directly, but rather it is called implicitly as part of a using or foreach statement, in which case the reverse-order pattern will naturally emerge, according to the statement embedding. 在大多数情况下,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.
}

Nested 'usings' shows you the 'outlived' is not really on, and rarely is (not to go and say never after 40 years of evidence).. And that includes the stack-based VM that runs on say CMOS. 嵌套的'使用'向你展示'过时'并不是真正开始的,而且很少(在40年的证据之后永远不会去说)。这包括基于堆栈的运行在CMOS上的虚拟机。

[ Despite some attempts by MSDN.com and Duffius to make it vanish, you know manage it all for you the difference between the heap and stack. [尽管MSDN.com和Duffius试图让它消失,但你知道管理堆栈和堆栈之间的差异。 What a smart idea.. in space ] 多么聪明的想法......在太空中]

"The runtime doesn't make any guarantees as to the order in which Finalize methods are called. For example, let's say there is an object that contains a pointer to an inner object. The garbage collector has detected that both objects are garbage. Furthermore, say that the inner object's Finalize method gets called first. Now, the outer object's Finalize method is allowed to access the inner object and call methods on it, but the inner object has been finalized and the results may be unpredictable. For this reason, it is strongly recommended that Finalize methods not access any inner, member objects." “运行时不会对调用Finalize方法的顺序提供任何保证。例如,假设有一个对象包含指向内部对象的指针。垃圾收集器检测到两个对象都是垃圾。 ,首先调用内部对象的Finalize方法。现在,允许外部对象的Finalize方法访问内部对象并在其上调用方法,但内部对象已经完成,结果可能无法预测。因此,强烈建议Finalize方法不要访问任何内部成员对象。“

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

So you can worry about your LIFO dispose semantics as much as you like, but if you leak one, the Dispose()'s are going to be called in whatever order the CLR fancies. 所以你可以随心所欲地担心你的LIFO处理语义,但是如果你泄漏了一个,那么Dispose()将以CLR所想的任何顺序被调用。

(This is more or less what Will said, above) (这或多或少会说,上面说)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM