C#:以与分配相反的顺序处理资源是否有优势?

发布于 2024-08-10 19:36:10 字数 254 浏览 7 评论 0原文

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

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

... do stuff ...

free( block2 );
free( block1 );

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

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. Is there any practical advantage to doing this in a C# /.NET application, or is this a habit that has outlived its relevance?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

南街九尾狐 2024-08-17 19:36:10

如果你的资源创建得很好,这应该不重要(太重要)。

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

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

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

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).

为你鎻心 2024-08-17 19:36:10

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

此外,如果您要处置 A 和 B 以及 A 引用 B,那么当您处理 A 时,如果 A 处置 B 也没关系 。 dispose A,因为 Dispose 方法应该可以多次调用而不会引发异常。

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.

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.

沫离伤花 2024-08-17 19:36:10

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

如果您指的是调用 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.
}

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.

In general, the order doesn't matter for most Framework objects, except to the extent that it matters to the calling code. 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.

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.

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.
}
琴流音 2024-08-17 19:36:10

嵌套的“使用”向您展示了“过时的”并没有真正存在,而且很少存在(不是说经过 40 年的证据证明永远不会)。这包括在 CMOS 上运行的基于堆栈的虚拟机。

[ 尽管 MSDN.com 和 Duffius 尝试让它消失,但您知道为您管理这一切,这就是堆和堆栈之间的区别。多么聪明的主意……在太空]

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.

[ 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. What a smart idea.. in space ]

日暮斜阳 2024-08-17 19:36:10

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

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

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

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

"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."

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.

(This is more or less what Will said, above)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文