C# 如何在.NET运行时调试内部错误?
我试图调试一些处理大文件的工作。代码本身可以工作,但是.NET运行时本身报告了零星的错误。对于上下文,这里的处理是一个1.5GB文件(只加载到内存一次)在循环中被处理和释放,故意试图重现这个不可预测的错误 我的测试片段基本上是:C# 如何在.NET运行时调试内部错误?,c#,.net,C#,.net,我试图调试一些处理大文件的工作。代码本身可以工作,但是.NET运行时本身报告了零星的错误。对于上下文,这里的处理是一个1.5GB文件(只加载到内存一次)在循环中被处理和释放,故意试图重现这个不可预测的错误 我的测试片段基本上是: try { byte[] data =File.ReadAllBytes(path); for(int i = 0 ; i < 500 ; i++) { ProcessTheData(data); // deserializ
try {
byte[] data =File.ReadAllBytes(path);
for(int i = 0 ; i < 500 ; i++)
{
ProcessTheData(data); // deserialize and validate
// force collection, for tidiness
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
}
} catch(Exception ex) {
Console.WriteLine(ex.Message);
// some more logging; StackTrace, recursive InnerException, etc
}
试试看{
byte[]data=File.ReadAllBytes(路径);
对于(int i=0;i<500;i++)
{
ProcessTheData(数据);//反序列化和验证
//强制收集,以保持整洁
Collect(GC.MaxGeneration,GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
}
}捕获(例外情况除外){
控制台写入线(例如消息);
//更多日志记录;StackTrace、递归InnerException等
}
(加入了一些时间和其他东西)
循环将在不确定的迭代次数下正常运行完全成功-没有任何问题;然后,该过程将突然终止。未命中异常处理程序。该测试确实涉及大量内存使用,但在每次迭代过程中,它都非常有效(没有明显的内存泄漏,我有足够的空间,在最差的点上有14GB未使用的主内存)。该进程是64位的
windows错误日志包含3个新条目,这些条目(通过退出代码80131506)表明执行引擎错误-一个令人讨厌的小家伙。表示GC错误,带有“修复”以禁用并发GC;但是,此“修复”并不能阻止该问题
澄清:此低级错误不会影响CurrentDomain.UnhandledException
事件
澄清:GC.Collect
仅用于监控锯齿状内存,检查内存泄漏并保持可预测性;删除它并不会使问题消失:它只会使它在迭代之间保留更多内存,并使dmp文件更大;p
通过添加更多控制台跟踪,我观察到它在以下每种情况下都会出现故障:
- 反序列化期间(大量分配等)
- 在GC期间(在GC“方法”和GC“完成”之间,使用GC通知API)
- 在验证期间(仅对部分数据进行
)-奇怪的是在验证期间GC“完成”之后foreach
我可以获得崩溃转储(dmp)文件;我如何进一步调查这一点,以了解系统在如此惊人地失败时正在做什么?尝试编写一个通用异常处理程序,看看是否有未处理的异常导致应用程序死亡
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
static void MyExceptionHandler(object sender, UnhandledExceptionEventArgs e) {
Console.WriteLine(e.ExceptionObject.ToString());
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
Environment.Exit(1);
工具->调试->常规->启用.Net Framework调试
+
Tools->IntelliTace->IntelliTaceEbents和呼叫信息
+
Tools->IntelliTace->在此目录中设置StorIntelliTace录制
然后选择一个目录
应该允许您进入.net代码并跟踪每个函数调用。
我在一个小样本项目上试用了它,效果很好
在每个调试会话之后,它将创建调试会话的记录。它是set目录
即使CLR死了如果我没弄错的话
这应该允许您在CLR崩溃之前访问extact调用。存在无法捕获的.NET异常。签出: 如果您有内存转储,我建议使用WinDbg查看它们,假设您还没有这样做 正在尝试运行注释
!EEStack
(混合本机和托管堆栈跟踪),并查看堆栈跟踪中是否有任何可能跳出的内容。在我的测试程序中,我发现有一次我的堆栈跟踪发生了FEEE(我故意破坏堆):
0:000> !伊斯塔克
---------------------------------------------
线程0
当前帧:ntdll!NtWaitForSingleObject+0xa
子SP RetAddr调用者,被调用者
00000089879bd3d0 000007fc586610ea内核库!WaitForSingleObjectEx+0x92,正在调用ntdll!NtWaitForSingleObject
000000 89879BD400 00000 7FC5869811C内核库!RaiseException+0x68,调用ntdll!RtlRaiseException
[...]
00000089879bec80 000007fc49109cf6 clr!WKS::gc_heap::gc1+0x96,正在调用clr!WKS::gc_堆::标记_阶段
00000089879BECD000007FC49109C21 clr!WKS::gc\U堆::垃圾收集+0x222,调用clr!WKS::gc_堆::gc1
00000089879BED1000007FC491092F1 clr!WKS::GCHeap::RestartEE+0xa2,调用clr!线程::恢复运行时
00000089879bed60 000007fc4910998d clr!WKS::GCHeap::GarbageCollectGeneration+0xdd,调用clr!WKS::gc_堆::垃圾_收集
00000089879BEDB000007FC4910DF9C clr!WKS::GCHeap::Alloc+0x31b,正在调用clr!WKS::GCHeap::垃圾收集生成
00000089879BEE0000007FC48FF82E1 clr!JIT_NewArr1+0x481
由于这可能与垃圾收集器的堆损坏有关,因此我将尝试!验证堆
命令。至少您可以确保堆是完整的(您的问题在别处),或者发现您的问题实际上可能是GC或某些P/Invoke例程破坏了它
如果您发现堆已损坏,我可能会尝试发现堆中有多少已损坏,您可以通过执行此操作!HeapStat
。不过,这可能只是显示整个堆在某一点上已损坏
很难通过WinDbg推荐任何其他方法来分析这一点,因为我对您的代码正在做什么或它是如何构造的没有真正的线索
我想如果您发现这是堆的一个问题,因此意味着这可能是GC的怪异之处,那么我将研究Windows的事件内跟踪
如果您得到的小转储没有剪切它,并且您使用的是Windows 7/2008R2或更高版本,那么如果您没有获得,则可以在进程终止时使用全局标志(gflags.exe)附加调试器,而不会出现异常 0:000> !EEStack --------------------------------------------- Thread 0 Current frame: ntdll!NtWaitForSingleObject+0xa Child-SP RetAddr Caller, Callee 00000089879bd3d0 000007fc586610ea KERNELBASE!WaitForSingleObjectEx+0x92, calling ntdll!NtWaitForSingleObject 00000089879bd400 000007fc5869811c KERNELBASE!RaiseException+0x68, calling ntdll!RtlRaiseException [...] 00000089879bec80 000007fc49109cf6 clr!WKS::gc_heap::gc1+0x96, calling clr!WKS::gc_heap::mark_phase 00000089879becd0 000007fc49109c21 clr!WKS::gc_heap::garbage_collect+0x222, calling clr!WKS::gc_heap::gc1 00000089879bed10 000007fc491092f1 clr!WKS::GCHeap::RestartEE+0xa2, calling clr!Thread::ResumeRuntime 00000089879bed60 000007fc4910998d clr!WKS::GCHeap::GarbageCollectGeneration+0xdd, calling clr!WKS::gc_heap::garbage_collect 00000089879bedb0 000007fc4910df9c clr!WKS::GCHeap::Alloc+0x31b, calling clr!WKS::GCHeap::GarbageCollectGeneration 00000089879bee00 000007fc48ff82e1 clr!JIT_NewArr1+0x481