【问题标题】:Why can't I investigate a dumpfile, using Windbg "!DumpHeap -stat" command?为什么我不能使用 Windbg "!DumpHeap -stat" 命令调查转储文件?
【发布时间】:2018-07-12 12:15:06
【问题描述】:

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

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

为了做到这一点,我想启动!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.dll\5A334E146eb000\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.dll\5A334E146eb000\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\10\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.dll\5A334E146eb000\SOS_x86_x86_4.7.2563.00.dll
0:000> .load C:\ProgramData\dbg\sym\SOS_x86_x86_4.6.1087.00.dll\583E5B8E6b1000\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.dll\5A334E146eb000\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.dll\583E5B8E6b1000\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.dll\583E5B8E6b1000\mscordacwks_x86_x86_4.6.1087.00.dll\mscordacwks_x86_x86_4.7.2563.00.dll, Win32 error 0n87

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

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

【问题讨论】:

  • .NET 进程的小型转储不能是小型的。它需要包括整个 GC 堆。与客户交谈,询问他们是如何创建它的。请记住,你得到这个小型转储是因为程序行为不端。有内存损坏问题的程序确实倾向于在 GC 发生的那一刻急剧下降。你必须知道你需要寻找什么来避免大海捞针的问题。这是一大堆。
  • @HansPassant:如果没有完整的堆信息,SOS 会在加载扩展时输出警告。

标签: clr windbg sos


【解决方案1】:

0:000> .load sos

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

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

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

垃圾收集器数据结构没有处于有效的遍历状态。

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

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

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

[...] 看起来由 .chain 结果确认:

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

让我们解决这个问题:[...]

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

这能解决问题吗?好像没有

如前所述,GC 现在可能正在运行。您可能对相关问题感兴趣:How to capture a process memory dump of a .NET process when .NET is not in the middle of a garbage collection (GC)

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

会不会是其他版本错了?

确实,CLR 似乎也指的是那个错误的版本。

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

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

.cordll -lp C:\ProgramData\dbg\sym\mscordacwks_x86_x86_4.6.1087.00.dll\583E5B8E6b1000\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 版本、本机调用堆栈等的更多信息,以便我们更好地帮助您(在发布新问题之前进行一些研究)

【讨论】:

  • 感谢您的精心回复。我正在查看您的发现,但就一般问题而言:似乎该过程可能处于垃圾收集的中间,这可能意味着转储已在错误的时间进行(但那么什么是正确的时间?:-))。另一方面,我是一名三线支持工程师,所以不是我负责转储:有一名一线支持工程师负责,他负责客户系统的转储,显然客户想知道并在他们的系统上完成所有事情的解释。
猜你喜欢
  • 2018-07-27
  • 2013-10-25
  • 2017-01-02
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-27
  • 1970-01-01
相关资源
最近更新 更多