我有一个应用程序似乎只在程序关闭后抛出异常。这是非常不一致的。 (我们都知道不一致的错误有多么有趣......)
我的猜测是在清理过程中出错。但是这些内存读/写错误似乎表明我的“不安全”代码使用中有问题(指针?)。
我感兴趣的是调试这些情况的最佳方法是什么?
如何调试已关闭的程序?
我正在寻找一个解决更大问题的起点。
这些错误似乎以多种方式呈现(一些运行时,一些调试):
1: .NET-BroadcastEventWindow.2.0.0.0.378734a.0: Application.exe - Application Error
The instruction at "0x03b4eddb" referenced memory at "0x00000004". The memory could not be "written". 2: Application.vshost.exe - Application Error
The instruction at "0x0450eddb" referenced memory at "0x00000004". The memory could not be "written". 3: Application.vshost.exe - Application Error
The instruction at "0x7c911669" referenced memory at "0x00000000". The memory could not be "read". 4: Application.vshost.exe - Application Error
The instruction at "0x7c910ed4" referenced memory at "0xfffffff8". The memory could not be "read".
答案 0 :(得分:6)
我使用AcrobarReader COM组件遇到了这个问题。在应用程序退出后不时出现“Application.vshost.exe - Application Error”“无法读取内存”。 GC.Collect()和WaitForPendingFinalizers()没有帮助。
我的google-fu带我到这个页面: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修改此过程。我只是希望它不会引入任何新的错误。
答案 1 :(得分:4)
如果您的应用是多线程的,那么您可能会收到来自工作线程的错误,这些错误未正确终止并尝试访问已处置的对象。
答案 2 :(得分:1)
我最近看到过这样的错误。我的问题与CRT(C运行时)与.NET运行时相互作用如何清理结束过程有关。我的应用程序很复杂,因为它是C ++,但允许加载COM加载项,其中一些是用C#编写的。
为了调试这个,我认为您将需要使用本机调试。 Visual Studio(设置为混合模式调试)或WinDbg。查找如何使用Microsoft公共符号服务器下载Windows组件的PDB - 您 需要 这些符号。
我们的许多问题都与.NET的(糟糕的)COM客户端支持有关。我说糟糕,因为它没有正确引用计数(没有开发人员的大量工作)。在完成垃圾收集之前,COM对象未被引用计数到零。这通常会在关机期间设置奇怪的计时问题 - COM对象应该在它们应该被清除之后很长时间。
答案 3 :(得分:1)
对于“不一致”而言,一个更高级的词是“非确定性的”。在.NET环境中非确定性地发生了什么?对象破坏。
当我遇到这种情况时,罪魁祸首就在我编写的类中,用于将不安全的调用包装到外部API。我将清理代码放在类的析构函数中,期望在对象超出范围时调用代码。但这不是.NET中对象破坏的工作原理,当一个对象超出范围时,它会被放入终结器的队列中,并且在终结器到达它之前不会调用它的析构函数。在程序终止之后,它可能不会这样做。如果发生这种情况,结果将与您在此处描述的内容非常相似。
一旦我完成了我的类实现IDisposable
,并在完成对象时显式调用Dispose()
,问题就消失了。 (实现IDisposable的另一个好处是你可以在using
块的开头实例化你的对象,并确信Dispose()将在代码离开块时得到。)
答案 4 :(得分:0)
尝试此操作以在程序控制下强制执行错误
//set as many statics as you can to null;
GC.Collect();
GC.WaitForPendingFinalizers();
} //exit main
答案 5 :(得分:0)
使用建议的代码后,错误停止显示:
GC.Collect();
GC.WaitForPendingFinalizers();