为什么我们不应该将代码放入类析构函数中来释放资源。 [英] why we should not put code into a class destructor to release resources.

查看:99
本文介绍了为什么我们不应该将代码放入类析构函数中来释放资源。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我正在阅读一篇关于垃圾收集的文章,其中有以下声明:

CLR在非确定性上运行以查看未使用的对象并清除它们。一个

这种非确定性特征的副作用是我们无法假设当一个对象被破坏时它会超出函数的范围。因此,我们不应该将代码放入class destructor

释放资源。


有人能解释一下这是什么意思吗?我没有得到这个副作用的含义以及为什么我们不应该将代码放入类析构函数来释放资源。

Recently I was reading one article on Garbage Collection, where below statement was there:
"CLR runs on non-deterministic to see the unused objects and cleans them. One
side effect of this non-deterministic feature is that we cannot assume an object is destroyed when
it goes out of the scope of a function. Therefore, we should not put code into a class destructor
to release resources."

Can someone explain me what does it mean? I am not getting the meaning of this side effect and why we should not put code into a class destructor to release resources.

推荐答案

这显然不是官方的MSDN措辞并不是很清楚。阅读这些:







此接口的主要用途是释放非托管资源。垃圾收集器会在不再使用该对象时自动释放分配给托管对象的内存。但是,无法预测垃圾收集何时发生。此外,垃圾收集器不了解非托管资源(如窗口句柄)或打开文件和流。



使用此接口的Dispose方法与垃圾收集器一起显式释放非托管资源。对象的使用者可以在调用此方法时调用此方法。不再需要对象。

- http://msdn.microsoft.com/en-us/library/system.idisposable(v = vs.110).aspx [ ^ ]







因为垃圾收集是非确定性的,所以你不确切知道垃圾收集器何时执行完成。要立即释放资源,您还可以选择实现dispose模式和IDisposable接口。 IDisposable.Dispose实现可以由类的使用者调用以释放非托管资源,并且可以使用Finalize方法在未调用Dispose方法的情况下释放非托管资源。

- http: //msdn.microsoft.com/en-us/library/system.object.finalize(v=vs.110).aspx [ ^ ]
That is obviously not the official MSDN wording and is not very clear. Read these:


"
The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed.
" -- http://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110).aspx[^]


"
Because garbage collection is non-deterministic, you do not know precisely when the garbage collector performs finalization. To release resources immediately, you can also choose to implement the dispose pattern and the IDisposable interface. The IDisposable.Dispose implementation can be called by consumers of your class to free unmanaged resources, and you can use the Finalize method to free unmanaged resources in the event that the Dispose method is not called.
" -- http://msdn.microsoft.com/en-us/library/system.object.finalize(v=vs.110).aspx[^]


When is is一个被破坏的对象?

简单:当垃圾收集器决定不再需要它时,可以安全地销毁它。



那么这是什么时候发生的?这是关键的问题。



所以让我们来看看Class实例的生命周期。



When is an object destroyed?
Simple: when the Garbage Collector decides it is no longer needed, and that it is safe to destroy it.

So when does that happen? That's the question which is key to this.

So let's look at the life cycle of a Class instance.

private void MyMethod
   {
   MyClass mc;
   ...



我们创建了一个可以引用类实例的变量 - 这不会创建实例of MyClass


We have created a variable that can reference a class instance - this does not create an instance of MyClass

private void MyMethod
   {
   MyClass mc = new MyClass();
   ...

现在我们在堆上创建了一个实例。

Now we have created an instance on the heap.

private void MyMethod
   {
   MyClass mc = new MyClass();
   ...
   }

现在,变量已超出范围,因此恢复了它使用的基于堆栈的内存。这不会破坏它所引用的基于堆的实例,因为它可以很容易地被其他变量引用 - 例如类级别:

Now, the variable has gone out of scope, so the stack-based memory that it used is recovered. This does not destroy the heap based instance it refers to because that could easily be referenced by other variables - class level for example:

private List<MyClass> list;
private void MyMethod
   {
   MyClass mc = new MyClass();
   list.Add(mc);
   ...
   }

该实例是否被引用,它是否被销毁,因为这将意味着引用计数,并且引入了它自己的问题(我不会进入这里) - 它在堆上等待,直到垃圾收集器摆脱它。只有当内存不足时才会发生这种情况。



因此,您的实例可能会持续数分钟,或数小时,或超过最后一次引用超出范围的天数。

如果你的班级掌握稀缺资源,并在析构函数中释放它们,它们可能会使用数周! :笑:

你应该做的是实现IDisposable,并在Dispose方法中释放它们。

whether the instance is referred to any more or not, it is not destroyed, because that would mean reference counting, and that introduces it's own problems ( that I'm not going into here) - it waits on the heap until the Garbage Collector gets rid of it. Which only happens when memory is running low.

So your instance may last minutes, or hours, or days past the point where the last reference to it went out of scope.
If your class holds onto scarce resources, and releases them in the destructor, they could be in use for weeks! :laugh:
What you should do is implement IDisposable, and release them in the Dispose method.


是的,不是一个非常明确的声明。这个问题对于理解来说非常复杂,但在实际应用中却相当容易。这个的含义大致是这样的:



可以分配的资源可以分为两类(这里我说的不是OOP类,而是数学类) ): 1)将通过垃圾收集器(GC)自动回收的那些,它是管理内存; 2) GC不会触及的那些。



类#1除了GC之外没有任何机制。当您创建引用对象(您需要知道引用与值对象,否则所有.NET编程都没有任何意义)时,您将分配内存,并且GC将释放内存。 />


因此,相关问题与#2 类有关。那是什么?它可以是托管内存,但也可能是其他任何东西。构建器创建大量临时文件并记住其名称的映像,因此最终需要在不需要时删除这些文件。这根本不是内存,因此GC不会删除它们。



如何处理这类资源。是的,如果您将清理代码放在析构函数中,则会发生清理。但这是一个问题。现在,关注:我们来到了关键问题。 如果一个对象是一个引用对象并且有一个析构函数,则意味着对象(来自类#1 )本身将被GC删除,没有别的。只有GC才会调用此析构函数。但你永远不知道它何时发生。



从堆中删除引用对象,当对象变得无法访问时回收内存。这是一个非常复杂的概念。例如,以循环方式创建3个对象A引用B,B引用C和C引用A.当您没有其他参考时,它们是否会被垃圾收集。是!对无法到达的检测是足够智能的。这个概念在这里解释:

http://en.wikipedia.org/wiki/Garbage_collection_ (computer_science) [ ^ ]。< br $>


-SA
Yes, not a very clear statement. The issue is pretty complicated for understanding, but quite easy when it comes to practical use. The meaning of this is, roughly, this:

The resources which can be allocated can be classified into two classes (here I talk not about OOP classes, but mathematical classes): 1) those which will be reclaimed automatically through Garbage Collector (GC), which is managed memory; 2) those which won't be touched by GC.

The class #1 does not have any mechanism except GC. When you create a reference object (you need to know reference vs. value objects, otherwise all .NET programming would not make any sense), you allocate memory, and the memory is deallocated by GC.

The issue in question is therefore, related to the class #2. What is that? It could be managed memory, but it also could be anything else. Imaging that your constructors creates a number of temporary files and remember their name, so eventually you need to delete the files when they are not needed. This is not memory at all, so GC won't delete them.

What to do with this kind of resources. Yes, if you put the clean-up code in a destructor, the clean-up will happen. But this is a problem. Now, attention: we came to the key issue. If an object is a reference object and has a destructor, it means that object (from class #1) itself will be removed by GC, nothing else. And only GC will cause the call of this destructor. But you never know when it happens.

The reference object is removed from heap and the memory is reclaimed when the object becomes unreachable. This is a pretty complex concept. For example, create 3 object A references B, B references C and C references A, in a circular manner. Will they be garbage-collected when you have no other references. Yes! The detection of the unreachable is intellectual enough. The concept is explained here:
http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)[^].

—SA


这篇关于为什么我们不应该将代码放入类析构函数中来释放资源。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆