C# IDisposable的理解


C#里可以嵌入非托管代碼,這就涉及到了這些代碼資源的釋放。以前總是看到別人的代碼里那么寫,也沒有好好想想為什么,今天看了書,總結一下。

資源釋放分為兩種:

  1. 托管的
  2. 非托管的

兩者的釋放方式不一致:

  1. 沒有非托管資源的,GC在運行時,會自動回收和釋放;
  2. 含有非托管資源的,必須提供一個析構器,他們也會在內存里停留的時間會更長,最終被加入一個叫做finalization queue的結構,然后由GC在另一個線程釋放;

實現IDispose接口是一種標准的釋放資源的方式,正確使用會減少很多的bug和因為資源釋放而引起的問題。正如上面所說,包含了非托管資源的代碼,是必須提供一個析構器的。這樣做的目的,是為了保證類的使用者,即使沒有顯式地調用Dispose方法,也可以正確地釋放資源。

生產環境中的代碼里,會有很多的繼承,因此為了保證子類在調用時能夠正確地執行父類的資源釋放,在標准模式中,將真正的資源釋放方法Dispose方法,抽象為一個virtual的方法,由子類去override,並在其中調用base的Dispose方法。

釋放資源的Dispose方法,應該完成以下幾件事(引用Effective C#)

  1. 釋放所有的非托管資源;
  2. 釋放所有的托管資源;
  3. 設定一個標志,標志資源是否已經銷毀;對於銷毀的對象,仍舊調用,則應拋異常;
  4. 跳過終結操作,調用GC.SuppressFinalize(this)方法。

以上,文字內容結束,基本的代碼如下:

 1 using System;
 2 using System.Diagnostics;
 3 
 4 namespace Learn
 5 {
 6     class Program
 7     {
 8         private static int Cnt = 100000;
 9 
10         static void Main(string[] args)
11         {
12             Stopwatch sw = new Stopwatch();
13             sw.Start();
14             for (int i = 0; i < Cnt; i++)
15             {
16                 IDisposeDerived de = new IDisposeDerived();
17             }
18             sw.Stop();
19             Console.WriteLine("total time is: " + sw.ElapsedMilliseconds);
20             Console.ReadLine();
21         }
22     }
23 
24     internal class IDisposeBase : IDisposable
25     {
26         // never add this unless unmanaged resources exist
27         // cauz this will add extra burdon and make negative influence on performance
28         //~IDisposeBase()
29         //{
30         //    Dispose(false);
31         //}
32 
33         private bool AlreadyDisposed = false;
34 
35         public void Dispose()
36         {
37             Dispose(true);
38             GC.SuppressFinalize(this);
39         }
40 
41         protected virtual void Dispose(bool shouldDisposeManagedReources)
42         {
43             if (AlreadyDisposed)
44                 return;
45             if (shouldDisposeManagedReources)
46             {
47                 // dispose the managed resources
48                 // release the events
49                 // etc.
50             }
51             // dispose the unmanaged resources
52 
53             // set the flag
54             AlreadyDisposed = true;
55         }
56 
57         public void MethodForPublic()
58         {
59             if (AlreadyDisposed)
60                 throw new Exception("object has been disposed!");
61             // do the normal things
62         }
63     }
64 
65     internal class IDisposeDerived : IDisposeBase
66     {
67         //~IDisposeDerived()
68         //{
69         //    Dispose(false);
70         //}
71 
72         private bool AlreadyDisposed = false;
73 
74         protected override void Dispose(bool shouldDisposeManagedReources)
75         {
76             if (AlreadyDisposed)
77                 return;
78             if (shouldDisposeManagedReources)
79             {
80                 // dispose managed resources
81             }
82             // dispose unmanaged resources
83 
84             // call the base's dispose method
85             base.Dispose(shouldDisposeManagedReources);
86 
87             // set the flag
88             AlreadyDisposed = true;
89         }
90     }
91 }

代碼里增加了包含析構器的實現,可以對比一下,性能差異十分明顯。

無析構器的實現結果:

有析構器的實現結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM