详解IDisposable和Finalize的意义

简介:

本文主要讨论IDisposable和Finalize如何释放资源,以及微软提供并推荐的一个标准IDisposable编程模式。

本文写的通俗易懂,如果你还看不懂,就自己去反省一下为什么自己水平这么烂....


IDisposable接口主要提供一个Dispose方法,该方法用来释放资源,准确的说是用来释放非托管资源。理论上不是必须有 IDisposable 接口,你也能自己设计出一个释放非托管资源的方法,但是使用这个接口的话,大家都统一使用,比较好理解,并且使用这个接口的类,可以使用using这种语法糖。

Finalize其实就是析构函数,学过C++的都知道啥叫析构函数,C#也一样。你必须显式的定义一个析构函数,这样,C#编译器才会生成一个Finalize方法。可以使用工具查看IL代码得到验证,IL代码显示了Finalize方法的结果是一个try finally结果,和using类似。

既然 IDisposable和Finalize都是回收非托管资源,那么为什么微软要提供雷同的功能呢?


IDisposable和Finalize确实雷同,但也有一些差别。

Dispose方法是主动调用(使用using也算主动调用),主动释放非托管资源。而析构函数是由GC回收托管资源的时候调用,因此何时调用是不可掌控的。因此完全依靠析构函数会导致出现非托管资源迟迟得不到释放,如果资源过大,堆积在内存增加内存泄露的风险。


也许有人会说,那我只要把非托管资源放到Dispose方法中,保证释放,那就不需要使用析构函数了。完全正确。但是前提是你保证释放了。假设你写了一个框架或者类库,其中使用了非托管资源,而且也必须显式调用Dispose才能释放掉。但是,假如某个2B程序员使用这个类库,他根本没考虑要手动释放资源,因此他在用你的类库后,发现经常内存动不动就满了或者连接数满了,然后就开骂你是各种2B,写的东西是一坨垃圾。


为了避免背这个黑锅,也避免被2B骂成2B,你可以依靠析构函数设置一个底线,就是在GC启动的时候也能触发一个动作去回收非托管资源,你就需要在Finalize中去做这些事情。


因此对于释放非托管资源,可以归结2个要点:

1,只实现Dispose方法,无法保证人人都会调用此方法,万一没调用,背黑锅的就是你。

2,只实现析构函数,可以保证回收非托管资源,但是无法掌握释放时机,因为GC何时触发析构函数是不确定的。运气不好的话,非托管资源长时间都得不到释放。

只有这2个方法同时使用,才能最大限度的释放非托管资源。因此微软提出了一个 IDisposable 编程模式。具体模式参考http://msdn.microsoft.com/en-us/library/system.idisposable.aspx



在这模式中:

如果用户调用了Dispose,则会调用Dispose(true),以此表示释放托管资源和非托管资源。并且注意GC.SuppressFinalize();方法很有必要,这个方法是压制了析构函数的调用,因为非托管资源以及释放,析构函数中的释放语句也没有必要执行了,一不小心可能还会导致错误。


如果用户没有调用Dispose,那么GC在回收资源的时候,会触发析构函数,注意,此时传入的Dispose(false);因为析构函数只负责释放非托管资源,不建议用析构函数去释放托管资源,因为析构函数调用时机是不确定的,托管资源很可能已经被释放掉了,从而导致一些异常的发生。

采用微软的模式简单有效,当然你也可以实现自己的模式,这就看各人需要了。



















本文转自cnn23711151CTO博客,原文链接: http://blog.51cto.com/cnn237111/1246402,如需转载请自行联系原作者


相关文章
|
7天前
|
缓存 Java
JVM对象引用
本次课程聚焦JVM对象引用,涵盖强引用、软引用、弱引用和虚引用。强引用是最常见的引用类型,确保对象不会被垃圾回收器回收,适用于需要确保对象存活的场景;软引用在内存不足时会被优先回收,常用于缓存;弱引用的对象随时可能被回收,适合临时对象;虚引用最弱,主要用于接收对象回收通知,进行资源清理。通过合理选择引用类型,可优化内存管理,避免内存泄露。
|
2月前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
54 17
|
7月前
|
设计模式 编译器 C++
C++中的构造方法和析构方法详解
C++中的构造方法和析构方法详解
52 0
|
7月前
|
Java 程序员 编译器
【C/C++析构函数 】C++中的“垃圾回收”机制_析构
【C/C++析构函数 】C++中的“垃圾回收”机制_析构
92 0
|
Java 数据库 Android开发
JVM 系列(6)吊打面试官:为什么 finalize() 方法只会执行一次?
JVM 系列(6)吊打面试官:为什么 finalize() 方法只会执行一次?
196 0
JVM 系列(6)吊打面试官:为什么 finalize() 方法只会执行一次?
|
Java
析构函数(方法)
析构函数(方法)
82 0
final, finally, finalize的区别。
final, finally, finalize的区别。
129 0
|
安全 C++ 容器
C++中的析构函数不要抛出异常
C++中的析构函数不要抛出异常
215 0
|
存储 安全 Java
final 、finally finalize 有什么不同?
final 、finally finalize 有什么不同?
218 0