析構函數與終結操做

建立對象的時候會調用構造函數初始化實例信息,固然析構函數就是釋放對象時作的一些釋放操做。數據庫

爲何須要析構函數,廣泛來講,由於咱們的對象中可能用到了一些非託管的代碼,譬如數據庫操做,網絡,本地文件等等,這些資源網絡

不是託管的,因此須要咱們的託管對象在銷燬時同事釋放那些以前使用到的非託管對象,不然一直未關閉,釋放,就可能致使泄漏。函數

若是你的對象中根本沒用到這些非託管資源,那麼請不要定義析構函數,畢竟有代價的。this

 

一、析構函數被編譯後,實際變成了Finalize()方法,因此實際上C#中也不容許你本身定義一個Finalize方法spa

二、.NET中的託管對象回收,都是經過垃圾回收機制來實現的,不用咱們手動就釋放。當CLR建立對象的時候,若是發現你定義了析構函數,也就是(Finalize方法),線程

那麼建立好對象的時候,會將對象地址另外放到一個「終結隊列」上;運行一點時間後,對象在根中沒法找到引用,且垃圾回收準備釋放該對象的時候,發現其在終結隊列有引用,code

則將其引用移動到「終結可達隊列」,也就是說通常若是是沒有析構方法的對象,此時就被回收了,可是有析構函數的對象,則不會被回收,只是將引用移動到「終結可達隊列「。對象

而後程序將繼續運行,固然CLR發現」終結可達隊列「有幾個對象的引用存在,則啓動一個單獨的線程,來遍歷隊列中的對象,執行其析構函數,並將引用從」終結可達隊列「清除。blog

Ok,這時譬如運行一點時間後,垃圾回收操做又開始清理了,這時候在回收其它垃圾對象的同時,會把以前」終結可達隊列「上的那些對象一併清除。隊列

也就是說有析構函數的對象,實際上要執行兩次的垃圾回收操做,才能釋放內存。全部有析構函數的對象時有代價的,可是又是必須的,畢竟確實須要釋放一些非託管的資源。

 

三、經過上面的那些過程瞭解到,析構函數無非是爲了當對象銷燬以前去作一些非託管資源的釋放,但卻所以提升了釋放的代價,

那麼假如咱們知道某個對象不須要非託管資源了,那麼其實就能夠手動去釋放,不比等到垃圾回收的時候去釋放。所以.NET提供了一個Dispose形式,調用Dispose來手動釋放非託管資源。可是嘛,析構函數仍是會照樣保存,以避免有些狀況忘記了去釋放,畢竟析構函數是是CLR調用的。也許你會想,那麼就算手動調用Dispose釋放了非託管資源,那麼

對象要回收的時候,CLR一樣調用了析構函數,那麼咱們的Dispose有什麼意義呢?實際上一般提供了Dispose形式的, 再Dispose方法內部的最後一般有那麼一句

GC.SupproseFinalize(this),也就是告訴CLR:好了,我已經本身去釋放非託管資源了,不須要你來釋放了,在垃圾回收的時候,你直接把對象回收了,不要給我再來添加到

「終結可達隊列」了。因此這樣當已經調用過Dispose操做的,就不會出現2次回收才釋放對象的狀況。

一般相似下面這樣的代碼

public class MyClass:IDispose

{  
     ~MyClass(){
    Dispose(false);//這個析構器是CLR調用的,默認仍是寫上,防止未手動釋放時,CLR能夠把非託管釋放
      }

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

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

     private void Dispose(bool bool1){
      if(bool1){
      //寫一點本身能控制的代碼
            }
           //釋放非託管資管
         GC.SupposeFinalize(this)//告訴CLR,釋放過了,不要再添加到「終結可達隊列」,直接銷燬內存
     }
}
相關文章
相關標籤/搜索