MiniDumpWriteDump和写同一次崩溃的多个转储?

时间:2013-04-29 06:26:55

标签: winapi visual-c++ crash-dumps minidump minidumpwritedump

TL; DR 为同一个崩溃事件编写多个转储是否有意义,如果是,那么您需要注意什么。


当我们的应用程序中存在未处理的异常/中止/您的名字时,我们正在使用MiniDumpWriteDump编写崩溃转储。

到目前为止,代码实际上写了两个转储

  • 一个MiniDumpWithDataSegs获得一个小的,可以通过压缩的电子邮件发送,一旦压缩就没有问题。
  • 我们需要一个完整的MiniDumpWithFullMemory来获取完整的信息。

为了完成这项工作,我们两次致电MiniDUmpWriteDump

1 Open/create file for small dump
2 Write small dump
3 Open/create file for large dump
4 Write large dump

据我所知,这个方案的一个 additinoal 想法是写小转储更快。基本上它总是亚秒级,而写入大型转储通常需要几秒钟,特别是当应用程序完全加载并且大转储很容易达到1.2 GB或更多时。

据我所知,首先编写小型转储的想法是,因为它更快,所以在崩溃的时间点崩溃过程需要更详细的快照,因为这个过程是多线程的

显然,进程的线程在第一次调用结束和第二次调用MDWP的开始之间继续运行,所以我们确实有一些情况下小转储中的信息实际上比大转储中的信息。

在考虑了这个之后,我会假设然而,要编写转储,MiniDumpWriteDump必须暂停进程的线程,所以如果我们要写大转储首先,我们会让大转储比小转储更准确。

问题

我们应该在小型转储之前编写大型转储吗?我们甚至应该写两个转储?我们能以某种方式让系统首先暂停进程的线程,然后写两个完全“同步”的转储吗?

3 个答案:

答案 0 :(得分:2)

我曾经分析过几年来各个客户的转储,以下只是我个人对你问题的看法,希望这会有所帮助。

我们应该在小型转储之前编写大型转储吗? 我不认为订单对于崩溃,挂起等典型问题很重要。崩溃点在那里,死锁存在于转储中,首先被捕获或之后。

我们是否应该写两个转储? 我建议写一个至少1个完全转储,小转储非常方便你得到一个问题的初步印象,但它是非常有限的esp。当你的应用程序崩溃。所以你可以建议客户给你发电子邮件小转储做第一轮分流,如果这不能帮助你找到根本原因,那就问完全转储。从技术上讲,您可以从完全转储中剥离一个小转储,但是,您可能不希望您的客户为您执行此类工作。所以这取决于您与客户的互动方式。

我们能否以某种方式让系统首先暂停进程的线程,然后编写两个完全“同步”的转储?

从技术上讲,这是可行的。例如执行out-proc相对容易,简单的NtSuspendProcess()挂起所有目标线程,但必须从另一个进程调用它。如果你喜欢在进程中,你必须枚举所有线程并调用SuspendThread(),这就是MiniDumpWriteDump()的工作原理。但是,我认为sync / asyn不会影响转储的准确性。

答案 1 :(得分:1)

不建议同时编写两个转储,因为MiniDumpWriteDump不是线程安全的。

  

所有DbgHelp函数(例如此函数)都是单线程的。因此,从多个线程到此函数的调用可能会导致意外行为或内存损坏。

是否应该使用小转储编写大型转储取决于您的应用程序和您可能期望的错误类型。 minidump仅包含堆栈信息,它不包含堆内存,句柄信息或最近卸载的模块。

获取堆栈信息显然会为您提供堆栈跟踪,但如果堆栈跟踪仅告诉您最后一个操作是引用堆上的某些内存,则跟踪没有多大用处。您预期的失败模式将决定哪个更有意义。如果您的遗留代码可能没有使用RAII来管理句柄,或者堆分配内存的处理不像您希望的那样进行管理,那么完整转储将非常有用。

您还应该考虑提交内存转储的人。如果您的客户在Internet上,他们可能不会喜欢提交大量的内存转储。他们可能还担心私有数据也可能与完整的内存转储一起提交。 minimdump更小,更容易提交,并且不太可能(尽管不是不可能)包含私有数据。如果您的客户在内部网络上运行,那么完全内存转储更容易接受。

最好首先编写一个minidump然后再编写一个大型转储。这样您就更有可能快速获取一些数据,而不是等待完全转储。完全转储可能需要一段时间用户经常不耐烦。他们可能决定终止这个过程,以便他们重新开始工作。此外,如果磁盘已满(可能是导致崩溃的原因),您可能更有可能获得小型转储而不是完全转储。

答案 2 :(得分:0)

DbgHelp.dll导入SuspendThread和ResumeThread。你可以做同样的事情。为所有线程调用SuspendThread(当然减去当前值),根据需要多次调用MiniDumpWriteDump,然后在挂起的每个线程上调用ResumeThread。这应该可以为您提供始终如一的精确转储。