首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#语言:垃圾收集,SuppressFinalize

C#语言:垃圾收集,SuppressFinalize
EN

Stack Overflow用户
提问于 2011-07-11 14:53:01
回答 5查看 3.5K关注 0票数 16

我正在阅读“C#语言”,第4版,它谈到垃圾收集如下:

"BILL :以下规则是C#与其他托管环境之间的一个重要区别。

在应用程序终止之前,将调用尚未被垃圾回收的所有对象的析构函数,除非这种清理已被抑制(例如,通过调用库方法GC.SuppressFinalize )。

我有几个问题要问:

  • Q1.为什么.net不同于其他托管环境(我认为这是在暗示Java?)这里?有什么特别的设计问题吗?

  • Q2.被称为GC.SuppressFinalize的对象会发生什么变化?据我所知,这意味着GC不会调用这些对象的终结器(析构函数),如果是,这些对象什么时候才会真正销毁,从而将分配的内存位返回到堆中?否则会有内存泄漏?
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-07-11 15:11:59

,GC.SuppressFinalize被调用的对象会发生什么变化?我知道这意味着GC不会调用这些对象的终结器(析构函数),如果是,这些对象什么时候才会真正被破坏?否则会有内存泄漏,对吧?

你对终结的目的有一个误解。终结是用于清理非托管内存的资源。

假设您有一个包含整数字段的引用类型的对象。这个整数字段恰好是一个文件的句柄,该句柄是通过调用非托管代码来打开该文件获得的。

由于其他程序可能希望访问该文件,因此尽快关闭该文件是礼貌的。但是.NET运行时不知道这个整数对操作系统有什么特殊意义。只是个整数。

解决此问题的方法通常是将对象标记为实现IDisposable,然后在处理完该对象后立即对其调用"Dispose“。您的"Dispose“实现将关闭该文件。

请注意,这里没有什么特别的事情。一个清理非托管资源的方法称为"Dispose“,需要释放的对象实现IDisposable,这只是一种惯例。垃圾收集部门对此一无所知。

所以现在问题出现了:如果有人忘了叫处分怎么办?文件会永远打开吗?(显然,当进程结束时,文件将被关闭,但如果进程运行很长时间,怎么办?)

要解决这个问题,您可以使用终结器。这是如何工作的呢?

当一个对象即将被垃圾收集时,垃圾收集器会检查它是否有终结器。如果是这样的话,那么它将把它放到终结器队列中,而不是垃圾收集。在将来的某个未指定的点,线程会运行一个线程来检查队列,并对每个对象调用一个特殊的"Finalize“方法。之后,对象将从终结队列中移除,并标记为“嗨,我已经完成了”。现在,该对象再次可用于收集,因此垃圾收集器最终运行并收集对象,而不将其放到终结队列中。

显然,“终结”和“处置”经常需要做同样的事情。

但现在出现了另一个问题。假设您处理了一个对象。现在不需要最后定稿了。终结是昂贵的;它使一个死对象存活的时间比它需要的时间长得多。因此,传统上,当处理对象时,Dispose的实现不仅关闭非托管资源,还将对象标记为“该对象已经完成,不要再次完成”。这样,垃圾收集器就不会将对象放到终结队列中。

所以让我们回答你的具体问题:

,GC.SuppressFinalize被调用的对象会发生什么变化?

当对象死后,垃圾收集器将简单地回收对象的内存,而不会将对象放到终结器队列中。

我知道这意味着GC不会调用这些对象的终结器

GC从不调用终结器。终结器线程是唯一调用终结器的东西。

,这些对象什么时候才会真正被摧毁?

你所说的“毁灭”是什么意思还不清楚。如果你的意思是“终结器什么时候运行?”答案是“永远不会”,因为你说要压制终结。如果您的意思是“什么时候才能回收托管堆中的内存?”,答案是“当垃圾回收器将对象标识为死的时候”。这将比正常情况下更早地发生,因为终结器队列将不会使对象处于活动状态。

票数 40
EN

Stack Overflow用户

发布于 2011-07-11 15:01:59

Q1:我怀疑这是因为它更关心实现出色的性能,而不是为简单性做出了相当大的牺牲。

Q2:由于一开始甚至不能保证调用终结器(即使SuppressFinalize不存在),所以只有在您已经释放了资源之后,才应该使用终结器。否则,您应该使用IDisposable来释放资源。

最后审定!=销毁

析构函数(在C++意义上)并不存在于.NET中--因为在某种意义上,每个对象都有一个称为垃圾收集器的“析构函数”。:)

C#所说的“析构函数”实际上是终结器。终结器用于处理对象分配的内存以外的其他内容,如文件句柄等。因此,并非每个对象都有终结器。内存总是由GC释放的,这样就不会有内存泄漏。

票数 5
EN

Stack Overflow用户

发布于 2011-07-11 14:55:40

我只知道第二个答案:SuppressFinalize is called when the object has already been destructed, i.e., by IDisposable.Dispose.,所以它不应该再被破坏。

这是因为终结器是在非确定时间发生的资源清理。添加IDisposable是为了允许在特定、可预测的时间进行资源清理。

编辑:在进程终止时,内存泄漏是不重要的。当进程终止时,它的堆由Windows收集,所以一个对象的内存是否返回到堆并不重要。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6652044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档