这是几天前我发现的,从这个问题中我得到的确认不仅仅限于我的机器。
进行复制的最简单方法是启动Windows Forms应用程序,添加按钮并编写以下代码:
private void button1_Click(object sender, EventArgs e) {
MessageBox.Show("yada");
Environment.Exit(1); // Kaboom!
}
Exit()语句执行后,程序失败。在Windows窗体上,您会收到“错误创建窗口句柄”。
启用非托管调试可以使事情更加清晰。在COM模式循环正在执行,并允许待递送WM_PAINT消息。这对处置形式是致命的。
到目前为止,我收集到的唯一事实是:
- 它不仅限于与调试器一起运行。没有一个,这也会失败。同样糟糕的是,WER崩溃对话框显示了两次。
- 它与过程的复杂性无关。wow64层是非常臭名昭著的,但是AnyCPU构建会以相同的方式崩溃。
- 它与.NET版本无关,4.5和3.5崩溃的方式相同。
- 退出代码无关紧要。
- 在调用Exit()之前调用Thread.Sleep()不能解决该问题。
- 在Windows 8的64位版本上会发生这种情况,并且Windows 7似乎不会以相同的方式受到影响。
- 这应该是相对较新的行为,我之前从未见过。我没有看到通过Windows Update交付的相关更新,尽管更新历史记录在我的计算机上不再准确。
- 这是严重破坏行为。您将在AppDomain.UnhandledException的事件处理程序中编写这样的代码,并且崩溃的方式相同。
我对您可以采取什么措施来避免此崩溃特别感兴趣。特别是AppDomain.UnhandledException场景使我感到困惑;没有很多方法来终止.NET程序。请注意,在事件处理程序中对UnhandledException调用Application.Exit()或Form.Close()无效,因此它们不是解决方法。
更新:Mehrdad指出终结器线程可能是问题的一部分。我想我已经看到了,也看到了2秒超时的一些证据,表明CLR提供了终结器线程来完成执行。
终结器位于NativeWindow.ForceExitMessageLoop()中。这里有一个IsWindow()Win32函数,它大致与代码位置相对应,在32位模式下查看机器代码时,偏移量为0x3c。似乎IsWindow()处于死锁状态。我无法获得内部的良好堆栈跟踪,但是,调试器认为P / Invoke调用刚刚返回。这很难解释。如果您可以获得更好的堆栈跟踪,那么我很乐意看到它。矿:
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12() + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
在ForceExitMessageLoop调用上方没有任何内容,已启用非托管调试器。
This happens on the 64-bit version of Windows 8
·汉斯这样说!
Exit(0)
64位Win7上遇到过这种行为,“更改” ExitCode
现在Process.GetCurrentProcess().Kill()