为什么对于同一个进程,小型转储有时只有调用堆栈?

Why do minidumps only sometimes have call stacks, for the same process?

最近我们在生产中遇到了问题。我使用 ProcessExplorer 对其进行调试,在 cdb 中保存了一个小型转储并在 VS2015 中对其进行了分析。我可以在主线程上看到 clr 调用堆栈,其中包含我们代码中的符号。

为了学习更多,我创建了一个简单的程序,它会挂起(带有一些调用堆栈),如下所示(在 Release 中构建,构建后移动了源代码):

public class Program
{
    public static void Main(string[] args)
    {
        new Program().Run();
    }

    public void Run()
    {
        DoThing();
    }

    public void DoThing()
    {
        Task t = new Task(() =>
            {
                while (true)
                {
                }
            }
        );

        t.RunSynchronously();
    }
}

我随后通过三种方式创建了转储文件:

  1. 通过任务管理器
  2. 附加 cdb 和 .dump /ma
  3. 附加到 VS2015,破坏并保存转储文件

所有转储的大小都非常相似。当我在新的 VS2015 会话中打开它们时,只有最后一个方法向我显示主线程的 clr 调用堆栈。为什么是这样?我在 VS 中保存转储时没有看到调用堆栈,但是当我重新打开转储文件时看到了。

我如何保证在生产中创建转储时可以看到 clr 调用堆栈(当 VS 不可用时)。 另外,当我第一次使用 ProcessExplorer 和 cdb 在生产中创建转储文件时,为什么会得到 clr 调用堆栈?

更新:
我检查了转储文件中的字符串,它们都包含如下值:
<做事>b__2_0
做事
做事>b__2_0

我的问题是任务管理器或 cdb 创建的小型转储有主线程堆栈,例如:

ntdll.dll!778214d1()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
mscorlib.ni.dll!7279bbc0() 

而由 visual studio 创建的主线程堆栈如下:

DumpDiag.exe!DumpDiag.Program.DoThing.AnonymousMethod__2_0()
mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke()
mscorlib.dll!System.Threading.Tasks.Task.Execute()

这是因为我的 .net 进程是 32 位的,但我用 cdb 和任务管理器捕获的小型转储是 64 位的。我错误地使用了 x64 版本的 cdb,以及捕获 64 位转储的(默认)64 位任务管理器。

我在上面创建了单独的 32 位和 64 位版本的测试过程,并使用相关版本的 cdb、相关版本的任务管理器以及附加 Visual Studio 捕获了小型转储。此后所有转储都正确显示了 clr 调用堆栈。

更多信息:https://blogs.msdn.microsoft.com/tess/2010/09/29/capturing-memory-dumps-for-32-bit-processes-on-an-x64-machine/