日期:2014-05-17  浏览次数:21095 次

C#中关于资源释放的问题dispose
C#中非托管对象都需要手动释放内存,但是为什么有的托管对象也可以手动释放,既然托管对象GC会自动回收,那C#为什么还提供Dispose 方法,举个例子,当使用Pen 类创建一个对象后,在使用完成之后,需要对其Dispose,但是有时候我们自定义的类自己确不能够自动释放,包括一些基本类型的变量,那么在以后的开发中到底哪些是需要注意手动释放的,哪些可以等待GC,还有就是一直不大明白当调用窗体的Close 方法后,运行到 Dispose(bool disposing)方法后,这个bool类型的参数是怎么传进来的, base.Dispose(disposing);这个方法具体是怎么实现的……

------解决方案--------------------
对于.net平台的对象,也就是对于那些支持GC的对象,你不知道所谓 Dispose 的具体内涵是,就不要画蛇添足地去调用它。

你可以打开.net的源代码,看看任何一个具有(或者父类型具有) IDisposeable 接口的程序是怎样实现的。就算是.net framework是许多实习的大学生参与开发的,但是微软的产品经理们可不是什么实习生,(当时)微软的老板不是只会搞推销业务的软件研发外行,所以.net framework产品在类似的基础方面非常一致、清晰、千锤百炼。

.net框架中所有的这类对象,在 protected virtual void Finalize() 重写方法中都会调用 Dispose 方法。因此你无需写什么Dispose,在GC调用 Finalize 方法的时候也就会自动调用 Dispose。因此胡乱地“手动释放”除了会让程序变得缓慢,也没有什么好处。同时反过来说,在所有的Dispose方法的实现中,通常又会写
GC.SuppressFinalize(this);
这样的语句。因为一旦你手动调用过Dispose方法,那么它就告诉GC没有必要再调用Dispose方法了!

无参数的Dispose通常就是实现为
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

这样两句。一个代码不断copy复制,那么这就叫做“模式”。这只是说明产品经理希望产品开发中表现出同样的模式,这样就可以在单元测试中单独测试 Dispose(bool) 签名的代码的功能,特别是测试这个代码在并发使用环境下逻辑是否争取,而测试时不需要牵扯上GC过程。

最后回答你“什么时候手动调用Dispose方法才估算是画蛇添足”的问题。比如说 DbConnection 的大多数实现(例如 SqlConnection 类),由于它自动在底层隐藏着“连接池”机制的实现,那么如果程序不及时调用 Close,而是等着 GC 那种延迟清理垃圾的机制,那么就会造成“连接池满”的异常。因此你明明知道应该手动调用 Dispose 的时候,你读了 Dispose 里边的源代码以后,才应该在自己的代码中注意调用 Dispose。否则就是画蛇添足地调用 Dispose 了。
------解决方案--------------------
最后回答你“什么时候手动调用Dispose方法才估算是画蛇添足”的问题 -->
                               最后回答你“什么时候手动调用Dispose方法才不算是画蛇添足”的问题

原则就是:在.net中,没有必要调用Dispose的时候,你就不要调用它。因为那没有一点好处。
------解决方案--------------------
在.net中(在java中也是一样),GC机制是个非常重要的概念。你总是在没有必要时也去调用Dispose,这就好像是一个人总是在天气晴朗的日子里也要带上一把大雨伞。你可以想一下,程序中每小时有上千百次、上千万次不需要调用Dispose的代码的时候你调用了它,那么你就利用不到GC的(推迟、仅在必要时才释放对象)许多好处了。