2014-10-08 29 views
0

我有一個類實現IDisposable,因爲它使用來自GDI +的圖像資源(Bitmap類)。我用它來包裝所有那些噱頭LockBits/UnlockBits。它可以正常工作,無論是我撥打Dispose()還是using聲明。配置工作正常,但沒有終止

但是,如果我離開程序終止而不處置,我得到一個System.AccessViolationException。直覺上,我認爲GC會像我一樣調用Dispose,並且對象會優雅地釋放資源,但這不是發生的事情。爲什麼?


這裏的IDisposable代碼:

private bool _disposing = false; 

~QuickBitmap() { 
    Dispose(false); 
} 

public void Dispose() { 
    Dispose(true); 
    GC.SuppressFinalize(this); 
} 

private void Dispose(bool safeDispose) { 
    if (_disposing) 
     return; 

    SaveBits(); // private wrapper to UnlockBits 
    bytes = null; // byte[] of the image 
    bmpData = null; // BitmapData object 

    if (safeDispose && bm != null) { 
     bm.Dispose(); // Bitmap object 
     bm = null; 
    } 

    _disposing = true; 
} 

這裏的,當它工作的很好:

using (var qbm = new QuickBitmap("myfile.jpg")) 
{ 
    // use qbm.GetPixel/qbm.SetPixel at will 
} 

這裏的時候它不工作:

public static void Main (string[] args) { 
    // this is just an example, simply constructing the object and doing nothing will throw the exception 
    var qbm = new QuickBitmap(args[0]); 
    qbm.SetPixel(0, 0, Color.Black); 
    qbm.Save(); 
} 

完整EXCETION是(有沒有內部異常):

An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll 
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 

再現100%,甚至在不同的機器上。我弄清楚我們應該使用usingDispose(),不使用它是壞的和所有的東西。我只想知道:爲什麼會發生這種情況?爲什麼內存「受保護」?我違反了哪種訪問方式?

+0

只是好奇......你爲什麼認爲'LockBits'是「噱頭」? – 2014-10-08 17:39:59

+0

@EdS。因爲它需要我繼續使用'IntPtr'。我使用這個類來避免在更高級的類中使用'IntPtr'。 – Mephy 2014-10-08 17:40:59

+0

你沒有遵循規定的Dispose模式。 – 2014-10-08 17:41:51

回答

8

問題發生是因爲您在實現中包含了不必要的終結器。從終結器通常執行的代碼無法安全地訪問受管對象。對SaveBits的調用很可能會違反此規則使用託管對象,儘管您未包含該方法的代碼。

最好的解決辦法是簡單地從QuickBitmap刪除終結,因爲QuickBitmap類不直接自己的非託管資源。

+0

沒有直接擁有非託管資源的私有'Bitmap'? – Mephy 2014-10-08 17:38:29

+3

不,「位圖」是一個託管類,而不是非託管資源。一個未經調整的資源可能是'Marshal.AllocHGlobal'創建的一個'IntPtr',除了明確調用Marshal.FreeHGlobal'之外,它不會被任何其他方式釋放。 – 2014-10-08 17:39:55

+0

明白了,謝謝。 – Mephy 2014-10-08 17:41:34

0

整個IDisposable是優雅地清理非託管資源。非託管資源的字面定義是GC無法自行清理的資源。毫不奇怪,如果你不這樣做,它將無法自行清理它。可以通過GC完全清理的物體不需要一次性使用,而且這不需要手動處理。如果物體可以在沒有人工一次性清洗的情況下清理乾淨,那麼首先不需要實施IDisposable

+0

這根本不回答我的問題。我很清楚'IDisposable'和GC是什麼意思,我要找的是手動或從析構函數調用'Dipose'的區別。 – Mephy 2014-10-08 17:34:59

+0

@Mephy您問是否需要手動處理資源以確保資源得到處置。你這樣做,就是這樣。如果不需要實際使用,就不需要首先具有「IDisposable」接口。如果您需要確保清理髮生在非託管資源上,您需要手動處理它。這裏的所有都是它的。 – Servy 2014-10-08 17:38:20

相關問題