注:這里的文章從"zendy---勿在浮沙筑高臺---"復制,目的是讓我有一個比較充分的對這個問題的認識.
文章標題:對.net 垃圾回收的c#編程相關方面(finalize 和dispose(bool disposing)和 dispose())的一些理解體會
原文章地址:http://www.cnblogs.com/caomao/archive/2006/10/03/152505.html
finalize 和dispose(bool disposing)和 dispose() 的相同點:
這三者都是為了釋放非托管資源服務的.
finalize 和 dispose() 和dispose(bool disposing)的不同點:
finalize是crl提供的一個機制, 它保證如果一個類實現了finalize方法,那么當該類對象被垃圾回收時,垃圾回收器會調用finalize方法.而該類的開發者就必須在finalize方法中處理 非托管資源的釋放. 但是什么時候會調用finalize由垃圾回收器決定,該類對象的使用者(客戶)無法控制.從而無法及時釋放掉寶貴的非托管資源.由于非托管資源是比較寶貴了,所以這樣會降低性能.
dispose(bool disposing)不是crl提供的一個機制, 而僅僅是一個設計模式(作為一個idisposable接口的方法),它的目的是讓供類對象的使用者(客戶)在使用完類對象后,可以及時手動調用非托管資源的釋放,無需等到該類對象被垃圾回收那個時間點.這樣類的開發者就只需把原先寫在finalize的釋放非托管資源的代碼,移植到dispose(bool disposing)中. 而在finalize中只要簡單的調用 "dispose(false)"(為什么傳遞false后面解釋)就可以了.
這個時候我們可能比較疑惑,為什么還需要一個dispose()方法?難道只有一個dispose(bool disposing)或者只有一個dispose()不可以嗎?
答案是:
只有一個dispose()不可以. 為什么呢?因為如果只有一個dispose()而沒有dispose(bool disposing)方法.那么在處理實現非托管資源釋放的代碼中無法判斷該方法是客戶調用的還是垃圾回收器通過finalize調用的.無法實現 判斷如果是客戶手動調用,那么就不希望垃圾回收器再調用finalize()(調用gc.supperfinalize方法).另一個可能的原因(:我們知道如果是垃圾回收器通過finalize調用的,那么在釋放代碼中我們可能還會引用其他一些托管對象,而此時這些托管對象可能已經被垃圾回收了, 這樣會導致無法預知的執行結果(千萬不要在finalize中引用其他的托管對象).
所以確實需要一個bool disposing參數, 但是如果只有一個dispose(bool disposing),那么對于客戶來說,就有一個很滑稽要求,dispose(false)已經被finalize使用了,必須要求客戶以dispose(true)方式調用,但是誰又能保證客戶不會以dispose(false)方式調用呢?所以這里采用了一中設計模式:重載 把dispose(bool disposing)實現為 protected, 而dispose()實現為public,那么這樣就保證了客戶只能調用dispose()(內部調用dispose(true)//說明是客戶的直接調用),客戶無法調用dispose(bool disposing).
范例如下:
public class baseresource: idisposable
{
//析構函數自動生成 finalize 方法和對基類的 finalize 方法的調用.默認情況下,一個類是沒有析構函數的,也就是說,對象被垃圾回收時不會被調用finalize方法
~baseresource()
{
// 為了保持代碼的可讀性性和可維護性,千萬不要在這里寫釋放非托管資源的代碼
// 必須以dispose(false)方式調用,以false告訴dispose(bool disposing)函數是從垃圾回收器在調用finalize時調用的
dispose(false);
}
// 無法被客戶直接調用
// 如果 disposing 是 true, 那么這個方法是被客戶直接調用的,那么托管的,和非托管的資源都可以釋放
// 如果 disposing 是 false, 那么函數是從垃圾回收器在調用finalize時調用的,此時不應當引用其他托管對象所以,只能釋放非托管資源
protected virtual void dispose(bool disposing)
{
// 那么這個方法是被客戶直接調用的,那么托管的,和非托管的資源都可以釋放
if(disposing)
{
// 釋放 托管資源
othermanagedobject.dispose();
}
//釋放非托管資源
dounmanagedobjectdispose();
// 那么這個方法是被客戶直接調用的,告訴垃圾回收器從finalization隊列中清除自己,從而阻止垃圾回收器調用finalize方法.
if(disposing)
gc.suppressfinalize(this);
}
//可以被客戶直接調用
public void dispose()
{
//必須以dispose(true)方式調用,以true告訴dispose(bool disposing)函數是被客戶直接調用的
dispose(true);
}
}
上面的范例達到的目的:
1/ 如果客戶沒有調用dispose(),未能及時釋放托管和非托管資源,那么在垃圾回收時,還有機會執行finalize(),釋放非托管資源,但是造成了非托管資源的未及時釋放的空閑浪費
2/ 如果客戶調用了dispose(),就能及時釋放了托管和非托管資源,那么該對象被垃圾回收時,不回執行finalize(),提高了非托管資源的使用效率并提升了系統性能
可以參考sqlconnection對象的new, open, close(內部調用dispose())的使用經歷可以加深對他們的理解.謝謝!
新聞熱點
疑難解答