程序终止后抛出异常(遇到错误)

本文关键字:遇到 错误 抛出异常 终止 程序 | 更新日期: 2023-09-27 17:47:48

我有一个应用程序,它似乎只有在程序关闭后才会抛出异常。而且非常不一致。(我们都知道不一致的错误有多有趣…)

我的猜测是在清理过程中出现了错误。但这些内存读/写错误似乎表明我的"不安全"代码使用(指针?)有问题。

我感兴趣的是,调试这些情况的最佳方法是什么
如何调试已经关闭的程序
我正在寻找一个起点来解决一个更大的问题。

这些错误似乎以几种方式出现(一些运行时,一些调试):

1:.NET BroadcastEventWindow2.0.0.0.378734a。0:Application.exe-应用程序错误
"0x03b4eddb"处的指令引用了"0x00000004"处的内存。无法"写入"内存。2:Application.vshost.exe-应用程序错误
"0x0450eddb"处的指令引用了"0x00000004"处的内存。无法"写入"内存。3:Application.vshost.exe-应用程序错误
位于"0x7c911669"的指令引用了位于"0x00000000"的内存。无法"读取"内存。4:Application.vshost.exe-应用程序错误
"0x7c910ed4"处的指令引用了"0xfffff8"处的内存。无法"读取"内存。

程序终止后抛出异常(遇到错误)

我在使用AcrobarReader COM组件时遇到了这个问题。应用程序退出后,我不时会遇到"application.vshost.exe-应用程序错误"无法读取内存"。GC.Collect()和WaitForPendingFinalizers()没有帮助。

我的谷歌傅把我带到这个页面:http://support.microsoft.com/kb/826220.我修改了我的案例的方法3。

使用进程资源管理器,我发现AcroPDF.dll在Main函数的最后一行之前没有发布。所以,API调用来了。

DLLImports(DLLImport位于System.Runtime.InteropServices命名空间中):

<DllImport("kernel32.dll", EntryPoint:="GetModuleHandle", _
       SetLastError:=True, CharSet:=CharSet.Auto, _
       CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function GetModuleHandle(ByVal sLibName As String) As IntPtr
End Function
<DllImport("kernel32.dll", EntryPoint:="FreeLibrary", _
    SetLastError:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function FreeLibrary(ByVal hMod As IntPtr) As Integer
End Function

然后在应用程序退出之前:

Dim hOwcHandle As IntPtr = GetModuleHandle("AcroPDF.dll")
If Not hOwcHandle.Equals(IntPtr.Zero) Then
    FreeLibrary(hOwcHandle)
    Debug.WriteLine("AcroPDF.dll freed")
End If

此过程可以针对任何其他行为不端的dll进行修改。我只是希望它不会引入任何新的bug。

如果你的应用程序是多线程的,你可能会从没有正确终止并试图访问已处理对象的工作线程中得到错误。

我最近看到了很多类似的错误。我的问题与CRT(C运行时)与.NET运行时的交互如何清理关闭过程有关。我的应用程序很复杂,因为它是C++,但允许加载COM加载项,其中一些是用C#编写的。

要对此进行调试,我认为您需要使用本机调试。Visual Studio(设置为混合模式调试)或WinDbg。查找如何使用Microsoft公共符号服务器下载windows组件的PDB-您将需要这些符号。

我们的许多问题都与.NET(糟糕的)COM客户端支持有关。我说糟糕,因为它没有正确引用计数(没有在开发人员端做很多工作)。直到垃圾收集完成,COM对象才被引用,计数为零。这通常会在关闭期间设置奇怪的时间问题——COM对象在本应清理很久之后才被清理。

"不一致"的一个更流行的词是"非确定性"。在.NET环境中,非确定性会发生什么?对象销毁。

当这种情况发生在我身上时,罪魁祸首是我编写的用于包装对外部API的不安全调用的类。我将清理代码放在类的析构函数中,期望在对象超出范围时调用该代码。但在.NET中,对象销毁不是这样工作的。当一个对象超出范围时,它会被放入终结器的队列中,直到终结器找到它,它的析构函数才会被调用。它可能直到程序终止后才会这样做。如果发生这种情况,结果将与您在这里描述的非常相似。

一旦我让我的类实现了IDisposable,并在处理完对象后显式地调用了Dispose(),问题就消失了。(实现IDisposable的另一个优点是,您可以在using块的开头实例化对象,并确信当代码离开块时Dispose()会得到。)

尝试在程序控制下强制发生错误

   //set as many statics as you can to null;
   GC.Collect();
   GC.WaitForPendingFinalizers();
} //exit main

使用建议的代码后,错误停止出现:

GC.Collect(); 
GC.WaitForPendingFinalizers();