Login with your google account

今天在做内存释放的工作时,因为盲目相信经验和自己的理解,居然弄错了几个地方。一直以来,我以为Using statement结束后调用的是finalizer,还根据GC释放的原理:“如果对象的reference不为0,那么该对象永远不会被释放”大大的探讨了一翻工作中碰到的问题,结果后来被老大指出只要类实现了IDispose,那么using结束后是能够强制调用Dispose的。通过这个问题,也让我突然发现我对Dispose理解上的错误,重新思考了Dispose和Finalize的区别 -- Dispose和Finalizer的主要区别在于释放的时机:

Dispose是的主要目的是“立刻运行释放”,应该释放尽可能多的资源,但主要还是去释放“不立刻释放会影响进程运行”的资源,比如连接的关闭工作等。而一般托管对象能够被GC自动释放,而且一般不会影响当前软件运行,所以Dispose中不释放也不会影响系统运行。

而Finalizer中则基本上是释放“资源不被需要时”释放的资源。举个实际点的例子,LoadLibrary可以用来在运行时加载dll并调用其中的interfaces,但有个问题是我们很难控制何时unloadlibrary,因为这些interface在整个运行时都可能被调用到,由loadlibrary加载进来的interfaces只有在程序退出时才“不被需要”。在这种情况下我们就可以利用单例的finalizer去做unloadlibrary的工作,因为单例的生存周期是和整个appdomain一致的,当appdomain被unload时,interfaces和它所依附的单例自然也没有存在的必要了。(具体的解释看这里)另外,为了安全的原因,Finalizer也会顺带调用Dispose函数,以便在最后的释放时机把之前可能忘记释放的资源一并释放。

 

Dispose

Finalizer

不释放资源对进程的影响程度

资源生命周期

短,但频繁

长,约等于整个对象的生命周期

进程对资源的需求

临时的或离散的

需求时间长

释放的时机

一旦意识到资源的存在可能影响系统运行,由程序员手工显示释放

当对象的不可以访问时,即reference为0,由GC释放在未知时间释放。

传递给开发人员的信息

当前对象不关闭有危险

当前对象不要关闭,释放的工作我自己会处理!

还有一些释放时需要注意的地方:

  1. Dispose和finalize被调用了并不意味着对象本身也会在调用完毕后被系统释放掉,它们的主要目的是释放该对象中创建的可能影响系统的运行的资源。
  2. 如果Dispose释放的内容和Finalizer一致,那么可以在Dispose的最后调用GC.SuppressFinalize(this),他的作用是禁止GC释放对象时调用finalizer。
  3. using statement和调用dispose的是类似的的。在写这篇文章前还以为using结束后系统是异步调用Dispose,但根据msdn上的解释,他们两者一样,甚至编译器本身就是把using解释成调用dispose。所以,网上一些说法认为Using后要加GC.WaitForPendingFinalizers()也是不必要的。WaitForPendingFinalizers应该是和GC.Collect合用。
  4. using和dispose的区别就是using可以用来一次性Dispose多个对象,而不需要开发人员写上一排的xxx.Dispose()。

References:

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

No Comments 2009-04-01 19:16:46 by Homyu.Shinn