处理工作正常,但不是终止

时间:2014-10-08 17:26:08

标签: c# gdi+

我有一个实现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%。我确实知道我们应该使用usingDispose(),而不是使用它是坏事和所有这些。我只是想知道:为什么会这样?为什么内存“受到保护”?我违反了哪种访问权限?

2 个答案:

答案 0 :(得分:8)

出现问题是因为您在实现中包含了不必要的终结器。从终结器执行的代码通常无法安全地访问托管对象。虽然您没有包含该方法的代码,但SaveBits调用可能导致使用托管对象违反此规则。

最好的解决方案是简单地从QuickBitmap删除终结器,因为QuickBitmap类不直接拥有非托管资源。

答案 1 :(得分:0)

IDisposable的整个是优雅地清理非托管资源。非托管资源的文字定义是GC无法自行清理的资源。不出所料,如果你不这样做,它就无法自行清理它。可以通过GC完全清理的物体不需要是一次性的,这不需要人工处理。如果可以在没有手动一次性使用的情况下清理对象,那么首先就不需要实现IDisposable