我有一个实现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();
}
完整的例外是(没有内部例外):
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%。我确实知道我们应该使用using
或Dispose()
,而不是使用它是坏事和所有这些。我只是想知道:为什么会这样?为什么内存“受到保护”?我违反了哪种访问权限?
答案 0 :(得分:8)
出现问题是因为您在实现中包含了不必要的终结器。从终结器执行的代码通常无法安全地访问托管对象。虽然您没有包含该方法的代码,但SaveBits
调用可能导致使用托管对象违反此规则。
最好的解决方案是简单地从QuickBitmap
删除终结器,因为QuickBitmap
类不直接拥有非托管资源。
答案 1 :(得分:0)
IDisposable
的整个点是优雅地清理非托管资源。非托管资源的文字定义是GC无法自行清理的资源。不出所料,如果你不这样做,它就无法自行清理它。可以通过GC完全清理的物体不需要是一次性的,这不需要人工处理。如果可以在没有手动一次性使用的情况下清理对象,那么首先就不需要实现IDisposable
。