为什么我不能使用 Windbg“!DumpHeap -stat”命令调查转储文件?

Why can't I investigate a dumpfile, using Windbg "!DumpHeap -stat" command?

首先,我是不同 .NET 平台上的新手。

我正在尝试调查托管 .Net 应用程序的转储(我不知道版本),使用 Windbg

为此,我想启动 !DumpHeap -stat 命令。
起初,这不起作用,因为 sos 未加载:

0:000> !DumpHeap -stat
No export DumpHeap found
0:000> .load sos

不过,好像还有一个问题:

0:000> !DumpHeap -stat
The garbage collector data structures are not in a valid state for traversal.
It is either in the "plan phase," where objects are being moved around, or
we are at the initialization or shutdown of the gc heap. Commands related to 
displaying, finding or traversing objects as well as gc heap segments may not 
work properly. !dumpheap and !verifyheap may incorrectly complain of heap 
consistency errors.
Object <exec cmd="!ListNearObj /d b331dbb0">b331dbb0</exec> has an invalid method table.

在网上找了一些帖子,提到这个问题可能是版本不匹配导致的,看来.chain结果证实了这一点:

0:000> .chain
Extension DLL search Path:
    => Hereby my entire %PATH% environment variable
Extension DLL chain:
    C:\ProgramData\dbg\sym\SOS_x86_x86_4.7.2563.00.dllA334E146eb000\SOS_x86_x86_4.7.2563.00.dll: image 4.7.2563.0, API 1.0.0, built Fri Dec 15 05:16:06 2017
        [path: C:\ProgramData\dbg\sym\SOS_x86_x86_4.7.2563.00.dllA334E146eb000\SOS_x86_x86_4.7.2563.00.dll]
    sos: image 4.6.1087.0, API 1.0.0, built Wed Nov 30 05:49:55 2016
        [path: C:\Program Files (x86)\Windows Kits\Debuggers\x86\sos.dll]

如您所见,似乎确实存在版本不匹配问题:

C:\...\SOS (ALL CAPS) seems to be of version 4.7.2653
sos (small letters)   seems to be of version 4.6.1087

让我们解决这个问题:

0:000> .unload C:\ProgramData\dbg\sym\SOS_x86_x86_4.7.2563.00.dllA334E146eb000\SOS_x86_x86_4.7.2563.00.dll
0:000> .load C:\ProgramData\dbg\sym\SOS_x86_x86_4.6.1087.00.dll3E5B8E6b1000\SOS_x86_x86_4.6.1087.00.dll
// I found this file, somewhere on my PC, I just hope it's correct :-)

这是否解决了问题?好像不是:

0:000> !DumpHeap -stat
The garbage collector data structures are not in a valid state for traversal.
It is either in the "plan phase," where objects are being moved around, or
we are at the initialization or shutdown of the gc heap. Commands related to 
displaying, finding or traversing objects as well as gc heap segments may not 
work properly. !dumpheap and !verifyheap may incorrectly complain of heap 
consistency errors.
Object <exec cmd="!ListNearObj /d b331dbb0">b331dbb0</exec> has an invalid method table.

好的。所以还是没有办法。会不会是其他版本有问题?

0:000> .cordll
CLR DLL status: Loaded DLL C:\ProgramData\dbg\sym\mscordacwks_x86_x86_4.7.2563.00.dllA334E146eb000\mscordacwks_x86_x86_4.7.2563.00.dll

确实,CLR 似乎也指的是那个错误的版本。让我们解决这个问题:

0:000> .cordll -u
CLR DLL status: No load attempts

(先卸载当前的,再加载新的)

0:000> .cordll -lp C:\ProgramData\dbg\sym\mscordacwks_x86_x86_4.6.1087.00.dll3E5B8E6b1000\mscordacwks_x86_x86_4.6.1087.00.dll
// Again a file I found somewhere on my PC, but it seems not to be working:
CLRDLL: Consider using ".cordll -lp <path>" command to specify .NET runtime directory.
CLR DLL status: ERROR: Unable to load DLL C:\ProgramData\dbg\sym\mscordacwks_x86_x86_4.6.1087.00.dll3E5B8E6b1000\mscordacwks_x86_x86_4.6.1087.00.dll\mscordacwks_x86_x86_4.7.2563.00.dll, Win32 error 0n87

现在我别无选择:谷歌搜索 Win32 error 0n87 我发现有关错误参数的信息,转储调查出错,但无法加载此 CLR DLL。

有人可以帮我吗(也许我们可以先确定我需要选择哪个版本,我只是随机选择了:-))?
提前致谢

0:000> .load sos

该命令将从 WinDbg 插件目录加载 SOS 扩展。通常这是 .NET 1.x 的版本,当时没有随 .NET Framework 安装一起提供。

较新版本的 .NET 框架附带了合适版本的 SOS DLL。它安装在 .NET 框架目录中,而不是在 WinDbg 目录中。

稍后我们看到上面的命令加载了4.6.1087.0版本。我真的无法解释这个,除了文件是手动交换的。

The garbage collector data structures are not in a valid state for traversal.

如果互联网上说这可能是版本不匹配,那可能是真的 - 我无法判断。

另一种选择是,该语句完全正确,当前正在进行垃圾回收,因此堆不一致。

第三个选项与已写入 .NET 内存并破坏了一些堆信息的本机代码(C++ 或类似代码)有关。

[...] which looks to be confirmed by the .chain result:

因此,我们看到加载了 2 个版本的 SOS。一个显然已经加载了(例如 !analyze,你之前是 运行 吗?),另一个是由 .load sos 命令加载的。

Let's solve this: [...]

您正在尝试使用 .unload.load 解决问题。但是,这只会卸载一个 SOS DLL,然后再次加载第二个。如果您想要一个清晰版本的 SOS,您应该 .unload 编辑 2 次(所有 SOS DLL),然后加载正确的版本。

Does this solve the issue? It seems not

如前所述,GC 现在可能 运行ning。您可能对相关问题感兴趣:

通过查看本机调用堆栈 (~*k),应该可以确定 .NET 当前是否正在垃圾收集。

Could it be that there are other versions which are wrong?

Indeed, also CLR seems to be referring to that wrong version.

好吧,您从未确定(或至少没有告诉我们)进程中加载​​的 .NET 版本。做一个 lm vm clr 应该给你加载的版本(一个例外是长 运行ning 进程并且同时安装了更新,那么版本信息可能是错误的,因为它是从磁盘读取的捕获故障转储的时间)。

加载适当 SOS 的常用命令是 .loadby sos clr,它告诉 WinDbg 从 clr.dll 所在的完全相同的位置加载 SOS。如果故障转储来自您的计算机,这将起作用。如果您从其他人那里获得故障转储,它可能会更复杂。

.cordll -lp C:\ProgramData\dbg\sym\mscordacwks_x86_x86_4.6.1087.00.dll3E5B8E6b1000\mscordacwks_x86_x86_4.6.1087.00.dll

-lp 代表 从路径加载 但您指定了文件名。如果您查看错误消息,它显示 mscordacwks_x86_x86_4.6.1087.00.dll 两次。

但是,我怀疑更正 mscordacwks 是否有帮助 - 它从未抱怨它是错误的。错误消息如下所示:

CLRDLL: [...]\mscordacwks.dll:<loaded version> doesn't match desired version <expected version>

总结

  1. 如果只想要一个版本的SOS,请卸载所有其他版本
  2. 如果堆处于无效状态,则可能恰好是无效状态,而不是版本不匹配。另一种选择是一些在 .NET 堆中编写的本机代码导致堆损坏。
  3. 在垃圾收集未进行时捕获故障转储
  4. 向我们提供有关 CLR 版本、本机调用堆栈等的更多信息,以便我们更好地帮助您(在您 post 新问题之前做一些研究)