我正在调查虚拟地址空间碎片。我遇到的问题是对VirtualAlloc
的调用可能有很多来源(LOH,内存映射,......)
我可以从转储文件中识别该函数的调用者吗?弄清楚我的问题的来源?
答案 0 :(得分:1)
您必须为您的app启用gflags用户堆栈跟踪,您可以从命令行或WinDbg中执行此操作,如果来自WinDbg:
!gflag +ust
然后你需要为给定的堆积做!heap -s
和!heap -stat -h XX
将转储更具体的统计数据,我建议在这里执行内存转储.dump /ma c:\first.dmp
然后执行导致碎片,按ctrl+break
并再次输入!heap -s
并再次进入内存转储.dump /ma c:\second.dmp
,重新进入WinDbg。
内存转储和堆摘要的原因是您可以分析哪些堆正在增加或返回,打开转储并对这些快照执行分析,将结果转储到文本文件中并对结果执行差异。
因此,如果您确定了一个正在增加的特定堆块,那么您可以转储该块!heap -p -a xxxx
的每个分配,其中xxxx是您的堆块,我建议您设置WinDbg将输出写入文件,因为这将在第二个内存转储上重复.logfile c:\first.txt
重复并执行差异以查看正在发生的其他分配。
此外,您可以转储堆的统计信息,这将为您提供分配大小的细分,这也可能为您提供线索。无论如何,只要你有带有私有符号的pdbs,那么你就可以识别谁使用完整的调用栈进行分配。
修改强>
如果您可以获取虚拟地址,那么您可以使用!pte address
和pfn frameNum
转储其他信息,您可以从{{1}的结果中获取虚拟地址的页面帧编号}。
!pte
将显示有关虚拟内存使用情况的一些统计信息,但不会更多,另一个是您可以在调用!vm 1
时设置断点并转储调用堆栈和本地变量(如果使用) virtualAlloc
然后这将显示堆栈帧之间的字节距离,这可能表示大量分配,我会将此信息写入日志文件并稍后在2个转储之间进行比较。
答案 1 :(得分:0)
首先,您必须为OS组件和您的程序设置pdb符号:在符号路径窗口中设置字符串,如下所示
SRV * F:\符号\ websymbols * HTTP://msdl.microsoft.com/download/symbols
并添加程序私有符号的路径。 执行此操作后,您可以在命令kb上看到prety堆栈跟踪。堆栈中首次出现的程序是调用函数。