淺談.NET非託管資源垃圾回收與程式資源優化(弱引用)
程式的資源分為託管資源與非託管資源,CLR直接管理的資源就是託管資源,還有一類非託管資源如IO、Socket、AplicationContext、Regex、Stream流、資料庫操作等等,這些直接由系統管理佔用記憶體。在垃圾回收的時候,雖然垃圾回收器可以跟蹤封裝非託管資源的物件的生存期,但它不瞭解具體如何清理這些資源。 上一篇文章說了託管資源與垃圾回收,下面說說非託管資源垃圾回收:
我們知道回收一個資源需要呼叫它的finalize方法,但是finalize方法不是一個公用的方法,我們並不知道怎麼去呼叫它。.NET提供的 Object.Finalize 方法,它允許物件在垃圾回收器回收該物件使用的記憶體時適當清理其非託管資源。 預設情況下,Finalize 方法不執行任何操作。 如果您要讓垃圾回收器在回收物件的記憶體之前對非託管資源執行清理操作,您必須在類中重寫 Finalize 方法。(有人可能要問finalize方法和解構函式是一個嗎, 其實解構函式是隱式的對物件的基類呼叫了Object.Finalize方法)
來說說IDisposable介面,要提供顯示釋放或者關閉物件的能力,一個型別通常要實現一種被稱為Dispose的模式,Dispose模式定義了開發人員在實現型別的顯式資源清理功能時所需要遵循的一些約定,如果一個型別實現了Dispose模式,使用該型別的開發者就知道當物件不再被使用的時候如何顯式的釋放掉它所佔用的資源。
下面是一個簡單的例子:
上面的例子展示瞭如何手動清理記憶體,有任何建議請留言。<span style="font-family:Arial;font-size:12px;">public class Test:IDisposable { private Brush brush; private bool isDisposed = false; public Test(Brush br) { this.brush = br; } ~Test() { Dispose(false); //釋放非託管資源 } public void Dispose() { //因為物件的資源被顯式的釋放,所以這裡阻止垃圾回收器回收 GC.SuppressFinalize(this); Dispose(true); } public void Close() { Dispose(); } private void Dispose(bool disposing) { lock (this) { if(disposing) { //這裡釋放託管資源 } if(!isDisposed) { //這裡釋放非託管資源 } isDisposed = true; } } }</span>
還有一種比較常用的釋放非託管資源的方法 using 語句,using語句只能用於那些實現了IDisposable介面的型別(個人感覺using非常簡潔好用)
<span style="font-family:Arial;font-size:12px;"><span style="white-space:pre"> </span> using(FileStream fs = new FileStream("Test.txt",FileMode.Create)) { //FileStream 只在括號內有效 }</span>
再說一個弱引用,個人感覺弱引用在程式中也比較實用
什麼時候使用:一些資料,它們很容易建立但是卻需要大量記憶體。比如,我們想要知道硬碟中所有的目錄和檔案,用一個樹來表示,問題在於這個樹非常龐大需要內多記憶體。如果使用者轉而訪問程式其他部分,這個樹可能就不那麼必要,但是卻佔用很多記憶體。我們可能放棄這個樹的根的引用,如果使用者再需要就重新建立。這個時候,弱引用就派上用場了。
例子:
<span style="font-family:Arial;font-size:12px;">private void SomeMethod()
{
Object o = new Object();
WeakReference wr = new WeakReference(o); //這是個短弱引用(不做介紹了)
o = null; //移除物件的強引用
o = wr.Target;
if (o == null)
{
//出現過垃圾回收,物件的記憶體已經被回收
}
else
{
//未出現垃圾回收,我們可以使用變數o來訪問物件
}
}</span>
就寫到這裡吧,讀者若有高見可以留言討論