我已经取得了一个正在运行的进程的内存转储(任务管理器,右键单击“创建转储文件”),现在我正在使用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)
我希望,通过配置调试符号路径,可以揭示很多信息。
有人知道怎么做吗?
先谢谢你了
1条答案
按热度按时间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 *
并在等待时给自己喝杯咖啡。可能会透露很多信息。
当然。通过调试,你可以得到大量的信息。你什么都可以看一下。然而,当你面前有一个干草堆时,知道你在寻找什么总是好的。我还是不清楚。 * 为什么**你在调试?你在找什么?