在我的高级调试之旅中,我经常有朋友问我什么是工作集(内存),什么是提交大小,什么是虚拟大小,什么是工作集。 截图如下:
由于有很多朋友问,这些都不太容易用语言描述,所以我只是早上有时间系统地谈谈。
正如你们中的一些人可能知道的那样,内存中的虚拟地址分为三类。
reserved(预订地址) committed (提交地址) free (野生地址) 上面的 reservation + submission 就是我们的虚拟大小,即虚拟大小 = reserved + committed。
当然,言语是没有根据的,你要拿出证据,写一个x86 C测试**,参考以下内容:
static void main(string args)
运行后用windbg附加程序,使用!address -summary 将计算出的内存与 Process Explorer 工具显示的虚拟大小进行比较,如下所示
一些比较严肃的朋友可能会说:探险家显示163300,而 windbg 显示 163281,为什么还差了一点,其实这是不同工具的统计误差,仅此而已。
正如你们中的一些人可能知道的那样,程序占用的内存最终会落在三个地方:
物理内存模块虚拟内存页面文件物理文件映射文件这里的工作集特指物理内存模块,因为 Windows 有 mappedfile 文件映射(内存共享)机制,所以物理内存模块上的内存可以进一步分为自己的独占+大家共享,可能有些朋友比较困惑,截图如下:
在此图的基础上,它转换为技术术语:
Workding Set = WS Private + WS Shareable最后,我们还是用资源管理器来观察刚才的 C 程序,截图如下:
正如我们前面提到的,内存最终会落在三个地方,其中一个是虚拟内存(pagefile),它用于辅助物理内存,即页面文件Sys 默认在 C 盘上,截图如下:
有了这些基础,是时候想出一个公式了。
Private Bytes = WS Private + Pages Out (PageFile)上面的 pages out 是我对分页内存的定义,这个 private bytes 指标在内存泄漏的情况下特别有用,因为它可以深入了解当前程序是否有大量页面输出。
为了说明大量的页面交换内存,请编写一个不断倾注数据的示例。
internal class program "); console.writeline("成功!"); console.readline();
运行程序后,截图如下:
根据公式:pages out = private bytes - ws private,我们可以看到大约 29GB 必须存储在 pagefile 中。
本来想用wmic pagefile get value来查看当前机器的虚拟内存占用情况,发现有时候不准确,也没太深入挖掘,输出如下:
c:\users\administrator>wmic pagefile get /valueallocatedbasesize=49464caption=c:\pagefile.syscurrentusage=1473description=c:\pagefile.sysinstalldate=20230807095038.481750+480name=c:\pagefile.syspeakusage=1640status=temppagefile=false
但是,正如你所看到的,这个页面文件系统已经从开始到48G已经飙升到49G,其中大部分都被我的程序吞噬了。
这也是很多朋友会问的,WS Shareable 和 WS Shared 有什么区别,从字面上看:一个是可以被多个进程共享的内存页集合,一个是已经共享的内存页的集合。
你可能有点困惑,但没关系,你可以借助 vmmap 工具观察它。
启动 consoleapp6 进程观察
从图中可以看出,shareable=104k 和 shared=0k,这意味着什么?感谢 consoleapp6exe 是一个映射到内存的文件,占用了 104k 的物理内存,没有其他进程共享这块物理内存,所以此时是 shared=0,这里填写 shared 最简单的方法是打开多个 consoleapp6 实例。
打开多个 consoleapp6 进程观察,然后反复点击 consoleapp6 生成多个实例,再次使用 vmmap 观察,截图如下:
我尽力使用多种观察工具眼见为实希望你不要再对这些术语感到困惑,如果以后有人问类似的问题,你可以把这个问题扔过去,减轻你我的负担。