"私有数据"在VMMAP中定义了什么?

rb_*_*rb_ 8 c# c++ memory winapi vmmap

我正在使用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定义字段私有数据,继续将其称为私有内存,可能有点肛门投诉,但含糊不清).

现在我批评互联网的其余部分是为了让事情变得混乱和不正确...如果上面有什么内容没有意义,或者你可以向我展示相反的文档,或者你需要一个更明确的定义,让我知道,我也将自己列入违法者名单!我认为上半部试图向某人解释内存问题,在网上,确保我们都在谈论同样的事情.

最后这个问题:VMMap如何知道给定的内存区域是Thread Stack,具体来说呢?建议我可能永远找不到答案:/

UPDATE/EDIT:我发现通过打开gflags用户堆栈跟踪(gflags -i myapp.exe + ust),你可以增加私有数据的大小,我会假设这是回溯数据库,但是甚至没有gflags ,我仍在努力解决私人数据问题.

Shr*_*ike 6

Sasha Goldstein 在 DotNext 会议上关于 WinDbg 的演讲中提到了这个问题 - https://www.youtube.com/watch?v=8t1aTbnZ2CE。重点是在 WinDbg 的帮助下可以轻松回答这个问题。

为了回答 CLR 是否为其堆使用 VirtualAlloc,我们将使用打印当前堆栈(本机堆栈和托管堆栈)的脚本在此函数上设置断点。

bp kernelbase!VirtualAlloc ".printf \"allocating %d bytes of virtual memory\", dwo(@esp+8);.echo;  k 5; !clrstack; gc"
Run Code Online (Sandbox Code Playgroud)

这里:k 5打印本机调用堆栈的最后 5 帧并!clrstack(来自 SOS)打印托管堆栈。gc继续执行。

请注意,此脚本仅适用于 x86 进程。对于 x64,您将需要其他一些(注册表和调用约定不同)。

然后我创建了一个简单的程序,它分配一个对象并将其添加到列表中。

    static void Main(string[] args)
    {
        var list = new List<string[]>();
        while (true) {
            var a = Console.ReadLine();
            if (a == "q" || a == "Q") break;
            var arr = new string[100];
            list.Add(arr);
        }
    }
Run Code Online (Sandbox Code Playgroud)

在 WinDbg 下运行它并开始按 Enter。在某个时刻,断点命中 - 在 List 上扩展并在堆中分配额外内存:

在此输入图像描述

显然,CLR 使用 VirtualAlloc 为其堆分配内存。