3

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


MiniDumpWriteDump当我们的应用程序中存在未处理的异常 / 中止 / younameit 时,我们会使用它来编写故障转储。

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

  • 一个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

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

据我所知,首先编写小转储的想法是,因为它更快,它会在崩溃的时间点对崩溃的进程进行更详细的快照,因为该进程是多线程的。

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

考虑到这一点之后,我会假设要写入转储,MiniDumpWriteDump无论如何都必须挂起进程的线程,所以如果我们先写大转储,我们会让大转储比小转储更准确。

问题

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

4

3 回答 3

3

几年来我一直分析各种客户的转储,以下仅是我个人对您的问题的看法,希望对您有所帮助。

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

我们甚至应该写两个转储吗? 我建议至少写 1 个完整的转储,小转储非常方便您初步了解问题所在,但它非常有限,尤其是。当您的应用程序崩溃时。所以您可以建议客户通过电子邮件将小转储发送给您进行第一轮分类,如果这不能帮助您找到根本原因,请询问完整转储。从技术上讲,您可以从完整的转储中删除一个小转储,但是,您可能不希望您的客户为您做这种工作。所以这取决于你如何与客户互动。

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

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

于 2013-05-07T16:14:36.737 回答
2

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

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

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

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

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

最好先写一个小型转储,然后再写一个大型转储。这样,您更有可能快速获取一些数据,而不是等待完整转储。完全转储可能需要一段时间,用户通常不耐烦。他们可能会决定终止该进程,以便重新开始工作。此外,如果磁盘已满(可能是崩溃的原因),那么与完整转储相比,小型转储的空间可能会稍大一些。

于 2013-04-29T07:11:18.950 回答
0

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

于 2013-04-29T13:07:25.783 回答