博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IDispose和Finalize的区别和联系
阅读量:6708 次
发布时间:2019-06-25

本文共 4742 字,大约阅读时间需要 15 分钟。

今天看代码,看到IDispose然后牵涉到垃圾回收机制,最后又到Finalize折腾了一下午,现在终于了解.NET的一些运行机制了。

看到GC.SuppressFinalize方法(MSDN:中C#示例),代码如下:

using System; using System.ComponentModel; // The following example demonstrates how to use the // GC.SuppressFinalize method in a resource class to prevent // the clean-up code for the object from being called twice. public class DisposeExample {
// A class that implements IDisposable. // By implementing IDisposable, you are announcing that // instances of this type allocate scarce resources. public class MyResource: IDisposable {
// Pointer to an external unmanaged resource. private IntPtr handle; // Other managed resource this class uses. private Component component = new Component(); // Track whether Dispose has been called. private bool disposed = false; // The class constructor. public MyResource(IntPtr handle) {
this.handle = handle; } // Implement IDisposable. // Do not make this method virtual. // A derived class should not be able to override this method. public void Dispose() {
Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this);//问题2:在“Dispose()”中“GC.SuppressFinalize(this);”是什么意思? } // Dispose(bool disposing) executes in two distinct scenarios. // If disposing equals true, the method has been called directly // or indirectly by a user's code. Managed and unmanaged resources // can be disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference // other objects. Only unmanaged resources can be disposed. private void Dispose(bool disposing) {
// Check to see if Dispose has already been called. if(!this.disposed) {
// If disposing equals true, dispose all managed // and unmanaged resources. if(disposing) {
// Dispose managed resources. component.Dispose();//问题1:也就是为什么GC垃圾回收机制在回收对象的时候只回收或者释放非托管资源,而不回收托管资源? } // Call the appropriate methods to clean up // unmanaged resources here. // If disposing is false, // only the following code is executed. CloseHandle(handle); handle = IntPtr.Zero; } disposed = true; } // Use interop to call the method necessary // to clean up the unmanaged resource. [System.Runtime.InteropServices.DllImport("Kernel32")] private extern static Boolean CloseHandle(IntPtr handle); // Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method // does not get called. // It gives your base class the opportunity to finalize. // Do not provide destructors in types derived from this class. ~MyResource() {
// Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. Dispose(false);//问题1:为什么在析构函数中调用的是“Dispose(false);”? } } public static void Main() {
// Insert code here to create // and use a MyResource object. } }

产生了两个问题(代码中红色标注区域):

问题1:为什么在析构函数中调用的是“Dispose(false);”,也就是为什么GC垃圾回收机制在回收对

象的时候只回收或者释放非托管资源,而不回收托管资源?
问题2:在“Dispose()”中“GC.SuppressFinalize(this);”是什么意思?

上网搜了写资料,终于了解了这种设计的用意和优点:

参考资料:
http://baike.baidu.com/view/4471636.htm
http://www.360doc.com/content/11/0503/18/6075898_114106056.shtml

解答问题1:

在.NET的对象中实际上有两个用于释放资源的函数:Dispose和Finalize。Finalize的目的是用于释放非托管的资源,而Dispose是用于释放所有资源,包括托管的和非托管的。
在这个模式中,通过一个变量“disposing”来区分是客户调用(true)还是GC调用(false)。
这是因为,Dispose()函数是被其它代码显式调用并要求释放资源的,而Finalize是被GC调用的。
在GC调用的时候MyResource所引用的其它托管对象(component)可能还不需要被销毁,并且即使
要销毁,也会由GC来调用。因此在Finalize中只需要释放非托管资源即可。

解答问题2:

由于在Dispose()中已经释放了托管和非托管的资源,因此在对象被GC回收时再次调用Finalize是
没有必要的,所以在Dispose()中调用GC.SuppressFinalize(this)避免重复调用Finalize。

因此,上面的模式保证了:

  1、 Finalize只释放非托管资源;
  2、 Dispose释放托管和非托管资源;
  3、 重复调用Finalize和Dispose是没有问题的;
  4、 Finalize和Dispose共享相同的资源释放策略,因此他们之间也是没有冲突的。
在C#中,这个模式需要显式地实现,其中C#的~MyResource()函数代表了Finalize()。

优点:

1、如果客户没有调用Dispose(),未能及时释放托管和非托管资源,那么在垃圾回收时,还有机会执
行Finalize(),释放非托管资源,但是造成了非托管资源的未及时释放的空闲浪费。
2、如果客户调用了Dispose(),就能及时释放了托管和非托管资源,那么该对象被垃圾回收时,不回
执行Finalize(),提高了非托管资源的使用效率并提升了系统性能。

此外还有Close()方法,此方法一般和Open()方法配合来使用,对于数据库连接,一般可以逆向操作,比如打开->关闭,关闭->打开,而对于文件操作,一般是关闭文件,相当于Dispose(),而且有的用户更愿意使用Close()来释放资源,所以出现了一下这种相当于适配器模式的代码:

public void Close(){    Dispose(();}

最后还要再说一点,据MSDN上说C#不允许类实现Finalize()方法,所以用析构函数来代替。

记于此,勿忘。

2012.03.07 17:01

 

转载地址:http://hlnlo.baihongyu.com/

你可能感兴趣的文章
简单的 jQuery 浮动层随窗口滚动滑动插件实例
查看>>
我的友情链接
查看>>
Cocos2d-x3.2 Loading场景的设计
查看>>
Cocos2d-x3.2 多点触控
查看>>
企业Exchange邮件服务器搭建实例
查看>>
linux下 htop 工具简介
查看>>
Ubuntu 中文输入法安装
查看>>
服务交付经理的职责
查看>>
php-fpm监控监本
查看>>
xcode 弹出“could not change executable permission...
查看>>
Google Java编程风格指南中文版
查看>>
阿里云Linux一键安装LNMP环境使用
查看>>
EF数据库迁移
查看>>
ifconfig、ip命令详解、route路由配置、DNS配置
查看>>
redis持久化配置
查看>>
asp.net底层公共方法
查看>>
java 字符串连接
查看>>
数组的二分查找法
查看>>
Android之SurfaceView简单分析
查看>>
js-数值保留2位小数?
查看>>