应用程序是否有从非托管访问冲突异常中恢复的方法



我有一个C#应用程序,它使用了一些非托管GDI+功能,我得到了一个(非托管?)异常:

Log Name: Application
Source: .NET Runtime
Date: 7/1/2013 9:14:58 AM
Event ID: 1026
Task Category: None
Level: Error
Keywords: Classic
User: N/A
Computer: sth
Description:
Application: sth
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException

堆栈跟踪为:

at System.Drawing.SafeNativeMethods+Gdip.IntGdipDisposeImage(System.Runtime.InteropServices.HandleRef)
at System.Drawing.SafeNativeMethods+Gdip.IntGdipDisposeImage(System.Runtime.InteropServices.HandleRef)
at System.Drawing.Image.Dispose(Boolean)
at System.Drawing.Image.Dispose()
at “..()
at Aspose.Cells.Charts.Chart.ToImage(System.IO.Stream, Aspose.Cells.Rendering.ImageOrPrintOptions)

我能防止它完全崩溃吗?我试着在没有争论的情况下使用catch语句,但某事告诉我这是不够的。我用这些错误的代码制作了我自己的C++DLL,似乎什么都不起作用,除非DLL抛出一些东西:

__declspec(dllexport) void __cdecl Function1(void) // This doesn't get caught.
{
    char *chrs = new char[1000];
    delete []chrs;
    delete []chrs;
}
__declspec(dllexport) void __cdecl Function3(void) // This doesn't get caught.
{
    try
    {
        MessageBox(NULL, L"AAA", L"Caption", MB_OK);
        char *chrs = NULL;
        chrs[0] = 'a';
    }
    catch(...)
    {
        MessageBox(NULL, L"BBB", L"Caption", MB_OK); // I get no messagebox here... (probably it doesn't get caught)
    }
}
__declspec(dllexport) void __cdecl Function2(void) // This gets caught as a .NET Exception.
{
    throw "Oh My!";
}

那么,我能做些什么来防止我的EXE崩溃吗?

编辑

此外,System.AccessViolationException是否意味着这是一个托管异常?如果,是的,我想知道为什么我没有抓住它…我的代码被包装在try{}catch(){}。。。

EDIT2

我的猜测是GDI+破坏了堆,CLR稍后会检测到它并抛出异常。但它不能被抓住,因为它不是从试块内扔出来的。在这种情况下我能做点什么吗?

有些异常是令人讨厌的,它们表示程序中发生了非常严重的错误。有些人非常讨厌,完全不可能从这种情况中恢复过来。此网站的名称属于该类别。ExecutionEngineException也是如此。这些非常糟糕,以至于catch块仍然可以正常执行的几率为零。他们会立即终止你的程序。

System.AccessViolationException只是这个超级讨厌的下面的一根头发,我们称之为超级讨厌。这是处理器在发现无法再执行代码时生成的异常。对一个程序来说当然是致命的。有几个可能的原因,最典型的是无效的机器代码指令或对不可读或不写的内存位置的访问。堆损坏是导致内存访问问题的典型原因。

捕获异常在技术上是可能的,因为异常处理会使处理器远离无法再执行的代码,并迫使它在其他地方继续执行。因此CLR不会被迫终止程序。然而,这是一个非常强烈的迹象,表明你的程序的状态严重损坏。这种腐败很少是孤立的。

当你大量处理位图时,看到它爆炸,就说明了这种腐败。它很可能是一个已损坏的非托管堆,由GDI+用于存储位图的像素数据。这种损坏通常是由GDI+本身引起的,它可能是程序中运行的其他非托管代码,当它丢失指针时,会向堆中喷射垃圾。

你可以转动命运之轮,抓住例外。但是,每当你的程序访问破碎堆上的数据时,它就很有可能继续轰炸AV。轰炸OutOfMemoryException也是非常可能的。毕竟,您打算释放非托管内存,但这并没有实现。这种情况发生在之后,在那里它可以造成更多的伤害,并且提供更少的方法来诊断原因。就像终结器一样,它也会爆炸。这是致命的,当终结器抛出未处理的异常时,CLR会终止程序。

抓住它真的只是一个创可贴,你真的需要解决根本原因。然而,很难,代码中堆损坏触发AV的位置永远不会靠近导致损坏的代码。换句话说,怀疑GDI+是原因并不能帮助您找到原因。事实上,这是最不可能的原因,GDI+是一个经过大量测试的代码块,每天运行数十亿次。

如果您不怀疑自己的进程中存在非托管代码,则通过在另一台计算机上测试程序来隔离问题。例如,可以像使用OpenFileDialog时加载到进程中的坏shell扩展一样简单。如果这样做,那么通常需要为程序中使用的任何非托管代码编写单元测试。祝你好运。

最新更新