【发布时间】:2016-01-06 08:43:30
【问题描述】:
我正在使用 VMMap 分析混合模式(托管和非托管)应用程序中的虚拟/进程地址空间利用率。我了解 Windows VMM 和虚拟内存 API 的工作原理,我也了解堆内存 API 的工作原理。我已经查看了我正在使用的 CRT 实现(不是很详细)并且(我想我 - 这可能是我的失败)了解它如何使用上述 Win32 API。
我希望了解这个“私人数据”统计数据向我展示了什么。我的应用程序没有直接调用任何 Win32 内存 API 函数,它只在本机 C++ 中使用“malloc/new”,在 C# 中使用“new”(这将深入使用 Win32 内存管理 API)。
VMMap给出的“私有数据”的定义是:
私有内存是由 VirtualAlloc 分配的内存,而不是 由堆管理器或 .NET 运行时重新分配。它 不能与其他进程共享,对系统收费 提交限制,通常包含应用程序数据。
所以我想这个定义让我问,好吧,那么是谁在调用 VirtualAlloc?是堆管理器还是 .Net 运行时?
我可以获取一些已提交的私有数据的地址并使用 WinDbg 来找出......嗯......事实证明微软在他们的智慧中已经对 ntdll 公共符号进行了贵族化,所以 WinDbg 不能正常工作很好 - 如果需要,我可以提供更多详细信息,但基本上像 !address -summary 这样的命令由于缺少符号而不再起作用。
这个问题的另一种表达方式可能是:我可以编写哪些 C++ 或 C# 代码来导致该私有数据统计量增加或减少?还是这一切都由操作系统、C++ 运行时或 .Net 运行时管理,因此任由其一时兴起?
我可以从 VMMap 的性质(其他内存类型是互斥的)推断出这种“私有数据”,因此不能是以下任何类型的地址空间:
- 堆(请注意,这包括已提交和保留的堆空间 - 保留 通过调用 VirtualAlloc,如描述中所述 上面的私人数据)。
- 托管堆
- 堆栈
- 可分享
- 映射文件
- 图片
- 页表
- 无法使用
- 免费
(我找不到定义VMMap认为上述所有类型的在线帮助文件,但这里有一个下载帮助文件的链接:https://technet.microsoft.com/en-us/library/dd535533.aspx)
我注意到,在我的应用程序中,私有数据的 TOTAL(保留和提交)大小在我的应用程序生命周期内保持相当稳定,尽管堆/托管堆/堆栈大小按预期变化。我还注意到,在私有数据使用的约 250Mb 总量中,实际上只有约 33Mb 被提交。请注意,我的测量方法相当初级,因此值可能在我的每次测量之间发生变化,而我只是没有看到它(如果我知道这是在测量什么,我可以使用 DebugDiag 来获取进程的转储相关计数器达到一定的阈值,鸡和蛋)。
我目前的推测理论是,这是保留的空间,用于在本地(或我想是管理的?)堆达到其容量时增长,但我没有任何证据可以证明这一点。所以它仍然牢牢地留在投机堆中。
在互联网上搜索这方面的详细信息可能会很痛苦,那里有很多令人困惑的帖子/文章/博客,使用自引用定义(Performance Monitor 对工作集的定义的第一句话就是一个很好的例子),不完整或完全错误。许多地方模糊了定义或使用了不一致的术语(请注意,VMMaps 字段私有数据的定义继续将其称为私有内存,这可能有点令人反感,但含糊不清)。
现在我已经批评互联网的其他部分让事情变得混乱和不正确......如果上面有任何不合理的地方,或者你可以向我展示相反的文档,或者你需要更多明确的定义,让我知道,我也会把自己列入罪犯名单!我认为尝试在网上向某人解释记忆问题的前半部分是确保我们都在谈论同一件事。
最后这个问题:How does VMMap know a given memory region is Thread Stack, specifically? 表明我可能永远找不到答案:/
更新/编辑:我发现通过打开 gflags 用户堆栈跟踪(gflags -i myapp.exe +ust),您可以增加私有数据的大小,我假设这是回溯数据库,但是有即使没有 gflags,我仍然在努力解释私有数据。
【问题讨论】:
-
我目前在我的应用程序中遇到了一些非常相似的问题,实际上是在特定环境中导致 OutOfMemoryException。我设法手动创建了一些 C# 代码来 PInvoke VirtualAlloc(来自 kernel32.dll),它生成了相同的 VMMap 结果,分配了大量的“私有数据”(参见this link)。尽管如此,我仍然试图跟踪这个“私人数据”是从哪里分配的。我正在尝试使用 VMMap 来跟踪该数据,但到目前为止没有成功。
标签: c# c++ winapi memory vmmap