如何调试程序静默退出

程序的静默退出,俗称闪退,是一个令人郁闷的问题。闪退发生的时候,没有任何提示,也没有留下任何现场信息(除了闪退之前一些没什么用的日志),导致很难去定位和解决。

总的来说,闪退一般是在以下几种情况下出现的:

  • 程序发生异常。有些特殊的异常会使异常捕获机制失效,因此我们准备好的错误报告,甚至是Windows的错误报告都不能正常执行。有时在Windows事件查看器中能看到对应的程序异常记录,但是这个记录的信息量太少,不足以定位异常。

  • 程序被其它程序终止。听起来这有点匪夷所思,我的程序没有干任何坏事,为什么会无缘无故被终止?事实上这种情况确实发生过,举个例子:360安全卫士的某个版本会毫无预兆地终止企业微信。如果你恰好碰到了这样的问题,可以尝试把360安全卫士升级到最新版本。

  • 程序自行终止。有些(设计不合理的)程序会在某些不能继续执行的情况下调用TerminateProcess来终止自己。通常在终止之前程序要进行提示或者留下一点日志,以方便调试。然而有的程序的确会给自己带来麻烦,终止之前不留下一丝痕迹。

幸运的是,Windows已经针对闪退问题提供了专门的调试功能。这个功能需要使用GFlags工具来开启,GFlags包含在Windows SDK的Debugging Tools中,可以通过安装这个套件来获取。运行GFlags后,切换到Silent Process Exit标签(GFlags可以开启很多调试功能,闪退调试只是其中一个),参考下图来进行设置:

Silent Process Exit可以针对指定程序进行设置,也可以全局设置,一般只需要针对我们自己的程序设置即可。在Application Specific Settings的Image一栏,填入程序的可执行文件名称,然后按下TAB键,即可打开这个程序的设置。

在Reporting Mode一栏,首先勾选Enable Silent Process Exit Monitoring 选项,然后根据需要勾选其它四个选项。

  • Enable dump collection,勾选了该选项后,程序退出的时候生成dump文件。该选项可以保留退出时的现场环境,一般都要勾选。同时需要填写Dump Folder Location和Dump Type两栏。

  • Launch monitor process,勾选了该选项后,程序退出的时候会启动指定的进程来调试。如果已经勾选了生成dump,那么不太必要再启动调试器了。同时需要填写Monitor Process一栏。

  • Enable notification,勾选了该选项后,程序退出的时候会在系统任务栏区域弹出提示。实践发现这个选项有时不生效,程序闪退时没有提示。

  • Ignore Self Exists,勾选了该选项后,程序自行的退出会被忽略。如果不勾选,程序每次正常退出时系统都会根据前面三个选项进行处理,勾选这个选项可以避免不必要的骚扰。可是实践发现这个选项有时也会不生效,有些程序正常退出也会触发前面选项的处理。

这里以记事本程序notepad.exe为例子,按确定按钮保存设置。打开记事本,在任务管理器中结束它,此时系统任务栏会弹出提示:

在事件查看器中可以看到对应的记录。同时在C:\下生成了对应的dump文件:

Windows提供的这个调试功能非常方便,但是GFlags的使用方式仍有一定门槛,不是每个用户都能快速按照我们的指引来设置。为了节约沟通成本,最好能有一种自动化的方式来帮用户打开这个功能。事实上,GFlags是通过修改注册表来实现功能的,所以只要把对应的注册表项导出,再让用户导入即可。

以上面记事本的设置为例,对应的注册表项如下:

1
2
3
4
5
6
7
8
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe]
"GlobalFlag"=dword:00000200

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe]
"LocalDumpFolder"="C:\\"
"DumpType"=dword:00000121
"ReportingMode"=dword:00000006
"IgnoreSelfExits"=dword:00000001