debugging Windbg C#转储分析:如何检索对象所属的模块?

sg24os4d  于 2023-06-23  发布在  C#
关注(0)|答案(1)|浏览(160)

我已经取得了一个正在运行的进程的内存转储(任务管理器,右键单击“创建转储文件”),现在我正在使用Windbg调查它。
!Dumpheap -stat显示了大量的对象,它们似乎是14个条目的集合:!Dumpheap -stat的结尾如下所示(前两列包含超链接):

3f62cc58 70b7d878       68     
3f62cc9c 70b7d878       68     
3f62cce0 70b7d878       68     
3f62cd24 70b7d878       68     
3f62cd68 70b7d878       68

单击此类对象可显示以下内容:

0:000> !DumpObj /d 3f62ebb0
Name:        System.Object[]
MethodTable: 70b7d878
EEClass:     70754b80
Size:        68(0x44) bytes
Array:       Rank 1, Number of elements 14, Type CLASS (Print Array)
Fields:
None

点击“Print Array”(打印阵列),将显示:

0:000> !DumpArray /d 3f62ebb0
Name:        System.Object[]
MethodTable: 70b7d878
EEClass:     70754b80
Size:        68(0x44) bytes
Array:       Rank 1, Number of elements 14, Type CLASS
Element Methodtable: 70b7d824
[0] null
[1] 38f2cfd8
[2] null
[3] null
[4] null
[5] null
[6] null
[7] null
[8] null
[9] null
[10] null
[11] null
[12] null
[13] null

我想有更多的信息,更特别是那些东西是什么样的收藏。为了做到这一点,我考虑了加载调试符号并显示模块名称。

  • 显示模块名称:我该怎么做?如何查看对象属于哪个模块?
  • 加载调试符号:我该怎么做?我把一些“*.pdb”文件放在一个目录中,并将“File”、“Symbol File Path”填写为C:\Temp_Folder\C:\Temp_Folder\*,但在这两种情况下,模块都保持延迟:
0:000> lm
  start    end        module name
  00480000 004b8000   application_being_debugged   (deferred)             
  1ce60000 1ce63000   security   (deferred)             
  1d900000 1d91b000   opccomn_ps   (deferred)             
  1d930000 1d956000   opcproxy   (deferred)

我希望,通过配置调试符号路径,可以揭示很多信息。
有人知道怎么做吗?
先谢谢你了

nkkqxpd9

nkkqxpd91#

我已经采取了一个正在运行的进程的内存转储[…]
为了给出更好的指导,了解为什么创建内存转储是很重要的。只是为了好玩,为了学习还是为了做真正的分析?如果这是一个真正的分析,什么样的分析?您想了解内存使用率高、挂起、性能问题(CPU峰值)还是应用程序崩溃?
[...](任务管理器,右键单击“创建转储文件”,现在我正在使用Windbg研究它。
您没有报告转储有任何问题,但请注意,任务管理器不一定是最佳选择。任务管理器有两个版本,32位版本和64位版本,每个版本都以该位进行内存转储。看看other options for creating a crash dump,它可能更合适,这取决于为什么问题。
!Dumpheap -stat揭示了大量的物体,[…]
这很正常一个简单的HelloWorld风格的WinForms应用程序有一个空窗口,它有超过5000个对象,而你可能认为你只有一个窗体。
当你说“巨大”的时候,很难理解。在调试时最好做到精确。说“! Dumpheap列出了123.000.468个对象”。
!Dumpheap -stat的结尾如下所示
不,对不起。要么是你的应用程序中有什么东西最终被破坏了,要么这根本就不是!dumpheap -stat的输出。!dumpheap -stat有4列:
1.类型信息(MT =方法表)
1.物体计数
1.该类型的所有对象的总大小
1.对象的名称
您发布的内容可能是!dumpheap输出的一部分(没有-stat)。在没有事先知道要找什么的情况下,这通常不是很有用。
[...]这些东西是什么样的收藏品
System.Object[]是一个类型为System.Object的数组,在C#中通常声明为object[]。关于这个系列没有什么可说的了。
其他集合可以是System.Windows.Forms.Control[]或2D数组,如System.Int32[][]System.Collections.Generic.List'1[[System.Windows.Forms.Application+ParkingWindow, System.Windows.Forms]],这是C#代码中的通用List<ParkingWindow>
我已经考虑过加载调试符号
这是个好主意没有符号,调试就不值得。
显示模块名称:我该怎么做?
您可以使用lm显示模块。lmv提供版本号和日期信息。lmf给你完整的路径。您可以通过附加m modulename来筛选特定的模块。之前的任何命令。
如何查看对象属于哪个模块?
这不可能为什么?我没有推荐信,所以我们来猜一猜。
a)跟踪每个小对象的DLL将至少增加指针大小开销。对于4字节int,这可能是8字节。b)你会跟踪哪个DLL?调用堆栈上总是有几个DLL。一个模块调用另一个模块,另一个模块调用下一个模块。最后,您可能总是在Microsoft DLL中的某个地方结束,因为字符串、int和许多东西都来自那里。你不会想那样的在另一个极端,可执行文件是首先分配内存的主要原因。因此,要确定哪些程序集要跟踪,哪些程序集不希望出现在列表中并不简单。c)查看调用堆栈是一个相当昂贵的操作。这就是抛出大量异常会使应用程序变慢的原因。
总而言之,我认为为每个对象记录一个模块是不可行的。
我能想到的最接近的已经实现的是Heap Tagging by DLL,但它与Windows堆管理器一起工作,而. NET不使用。而且,您只知道哪个堆属于哪个DLL,而不知道对象。
加载调试符号:我该怎么做?
通常两个步骤就足够了:
1.使用Microsoft符号:.symfix
1.添加您的符号:.sympath+ C:\some\directory
有关详细信息,请参阅How to set up symbols,其中解释了更多详细信息。
一些“. pdb”文件
不是一部分。全部用。
C:\Temp_Folder\*
您不需要使用通配符。只需指定目录。
模块保持延迟
这是想要的。加载符号缓慢。它们将在需要时加载。如果你想现在加载它们,请使用ld *并在等待时给自己喝杯咖啡。
可能会透露很多信息。
当然。通过调试,你可以得到大量的信息。你什么都可以看一下。然而,当你面前有一个干草堆时,知道你在寻找什么总是好的。我还是不清楚。
* 为什么**你在调试?你在找什么?

相关问题