我正在调查虚拟地址空间碎片。我遇到的问题是调用VirtualAlloc
可以有很多来源(LOH,内存映射,...)
我可以从转储文件中识别函数的调用者吗?以某种方式找出我的问题的根源?
我正在调查虚拟地址空间碎片。我遇到的问题是调用VirtualAlloc
可以有很多来源(LOH,内存映射,...)
我可以从转储文件中识别函数的调用者吗?以某种方式找出我的问题的根源?
您必须为您的应用启用 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
。
内存转储和堆摘要的原因是您可以分析哪些堆正在增加或返回,打开转储并对这些快照执行分析,将结果转储到文本文件中并对结果进行比较。
因此,如果您确定了一个正在增加的特定堆块,那么您可以转储该块的每个分配,!heap -p -a xxxx
其中 xxxx 是您的堆块,我建议您设置 WinDbg 以将输出写入文件,因为这将非常大.logfile c:\first.txt
在第二块内存上重复非常大转储并进行比较以查看正在发生的其他分配。
您还可以转储堆的统计信息,这将为您提供分配大小的细分,这也可能为您提供线索。无论如何,只要您拥有带有私有符号的 pdb,那么您就可以确定谁使用完整的调用堆栈进行了分配。
编辑
有一篇文章可以帮助你: http ://bugslasher.net/2011/01/15/memory-exhaustion-even-if-a-large-enough-free-memory-segment-is-available/
如果您可以获得虚拟地址,那么您可以使用转储附加信息!pte address
,pfn frameNum
您可以从结果中获得虚拟地址的页框号!pte
。
!vm 1
将显示一些有关您的虚拟内存使用情况的统计信息,但仅此而已,另一件事是您可以在调用上设置断点virtualAlloc
并转储调用堆栈和局部变量,如果您使用kf
,那么这将显示堆栈帧之间的字节距离可能表明分配较大,我会将此信息写入日志文件,并稍后在 2 个转储之间进行比较。
首先,您必须为操作系统组件和程序设置 pdb 符号:在符号路径窗口中设置字符串,如下所示
srv*f:\symbols\websymbols*http://msdl.microsoft.com/download/symbols
并添加路径到您的程序私有符号。执行此操作后,您可以在命令 kb 上看到漂亮的堆栈跟踪。您的程序在堆栈中的第一次出现是调用者函数。