一:背景

1. 讲故事

在高级调试的旅程中,经常会有一些朋友问我什么是 工作集(内存),什么是 提交大小,什么是 Virtual Size, 什么是 Working Set 。。。截图如下:

既然有很多朋友问,这些用口头也不怎么好描述,刚好上午有时间就系统的聊一下吧。

二:内存术语解读

1. Virtual Size 是什么

可能有些朋友知道,内存中的虚拟地址被划分成了三类。

  • Reserved (预定地址)
  • Committed (提交地址)
  • Free (蛮荒地址)

上面的 预定+提交 就是我们的 Virtual Size,即 Virtual Size = Reserved + Committed

当然口说无凭,得要拿出证据,写一个 x86 的 C# 测试代码,参考如下:


static void Main(string[] args)
{
Console.WriteLine("hello world!");
Console.ReadLine();
}

将程序跑起来后用 windbg 附加,使用 !address -summary 将计算出的内存和 Process Explorer 工具显示的 Virtual Size 进行对比,截图如下:

有些较真的朋友可能说:Explorer 显示出的是 163.300,而 windbg 显示的是 163.281 ,为什么还差一点点,其实这是不同工具的统计误差,仅此而已。

2. Working Set

有些朋友可能知道,一个程序所占的内存最终会在三个地方落地:

  • 物理内存条
  • 虚拟内存 pagefile
  • 物理文件 MappedFile

这里的 Workding Set 特指的就是 物理内存条 ,由于 Windows 有 MappedFile 这种文件映射(内存共享)机制,所以物理内存条上的内存可以进一步划分为 自己独占的 + 大家共享的,可能有些朋友比较蒙,截个图如下:

有了这张图的基础,转化为专业术语就是:

  • Workding Set = WS Private + WS Shareable

最后我们还是用 Explorer 观察下刚才的 C# 程序,截图如下:

3. Private Bytes

刚才我们说到了内存最终会落地到三个地方,其中一个地方就是 虚拟内存(pagefile),简而言之它的作用就是给物理内存打辅助,这个 pagefile.sys 默认是在 C 盘上,截图如下:

有了这些基础,就可以列出一个公式了。

  • Private Bytes = WS Private + Pages Out (pagefile)

上面的 Pages Out 是我定义的换页内存,这个 Private Bytes 指标在分析内存泄露的场景下特别有用,它能够准备的洞察当前程序是否存在大量的 Pages Out(换页内存)

为了方便演示出现了大量的换页内存,写一个不断灌数据的例子。


internal class Program
{
static void Main(string[] args)
{
var list = new List<string>(); for (int i = 0; i < 100000000; i++)
{
list.Add(string.Join(",", Enumerable.Range(0, 100000))); if (i % 10000 == 0) { Console.WriteLine($"i={i}"); }
}
Console.WriteLine("成功!"); Console.ReadLine();
}
}

将程序跑起来后,截图如下:

根据刚才的计算公式:Pages Out = Private Bytes - WS Private ,可以得知大概有 29G 不得不存放在 pagefile 中。

本来想用 wmic pagefile get /value 看一下当前机器的虚拟内存占用,发现有时候不准,我也没太深究了,输出如下:


C:\Users\Administrator>wmic pagefile get /value AllocatedBaseSize=49464
Caption=C:\pagefile.sys
CurrentUsage=1473
Description=C:\pagefile.sys
InstallDate=20230807095038.481750+480
Name=C:\pagefile.sys
PeakUsage=1640
Status=
TempPageFile=FALSE

不过可以看到,这个 pagefile.sys 已经从刚开始的 4.8G 暴涨到 49G 了,其中一大半都被我的程序吞掉了。

4. WS Shared

这个也是很多朋友会问的,WS ShareableWS Shared 到底有什么区别,从字面意思上看就是:一个可被多个进程共享的内存页集合中,当前已经被共享的内存页集合。

可能这么说大家有点懵逼,不过没关系,可以借助 VMMap 工具观察。

  1. 开启一个 ConsoleApp6 进程观察

从图中可以看到 Shareable=104k,而 Shared=0k ,这是什么意思呢? 由于 ConsoleApp6.exe 是文件映射到内存的,占用了 104k 的物理内存,此时没有其他进程共享这一块物理内存,所以此时为Shared=0,要想把这里的 Shared 也给填充起来,最简单的办法就是开启多个ConsoleApp6实例。

  1. 开启多个 ConsoleApp6 进程观察

接下来反复点击 ConsoleApp6 生成多个实例,再次使用 VMMap 观察,截图如下:

三:总结

我尽最大努力通过多个观察工具用眼见为实的方式把这几个内存指标系统的说了一下,希望大家对这几个术语不再迷茫,以后有人问类似问题就可以把这篇丢过去,减轻了你我负担...

聊一聊 .NET高级调试 中的一些内存术语的更多相关文章

  1. Linux高级调试与优化——内存管理

    1.物理地址和虚拟地址 Linux采用页表机制管理内存,32位系统中页大小一般为4KB,物理内存被划分为连续的页,每一个页都有一个唯一的页号. 为了程序的的可移植性,进程往往需要运行在flat mem ...

  2. IDA动态调试技术及Dump内存

    IDA动态调试技术及Dump内存 来源 https://blog.csdn.net/u010019468/article/details/78491815 最近研究SO文件调试和dump内存时,为了完 ...

  3. Linux高级调试与优化——gdb调试命令

    番外 2019年7月26日至27日,公司邀请<软件调试>和<格蠹汇编——软件调试案例集锦>两本书的作者张银奎老师进行<Linux高级调试与优化>培训,有幸聆听张老师 ...

  4. .NET高级调试系列-Windbg调试入门篇

    Windbg是.NET高级调试领域中不可或缺的一个工具和利器,也是日常我们分析解决问题的必备.准备近期写2篇精华文章,集中给大家分享一下如果通过Windbg进行.NET高级调试. 今天我们来一篇入门的 ...

  5. 玩好.NET高级调试,你也要会写点汇编

    一:背景 1. 简介 .NET 高级调试要想玩的好,看懂汇编是基本功,但看懂汇编和能写点汇编又完全是两回事,所以有时候看的多,总手痒痒想写一点,在 Windows 平台上搭建汇编环境不是那么容易,大多 ...

  6. [Android Studio 权威教程]断点调试和高级调试

    好了开始写一个简单的调试程序,我们先来一个for循环 ? 1 2 3 4 5 6 7 8 <code class="language-java hljs ">for ( ...

  7. android 中如何分析内存泄漏

    转载:http://blog.csdn.net/fulinwsuafcie/article/details/8363218 前提条件: 1,电脑安装了java 运行环境 2,手机端开启了 USB 调试 ...

  8. 理论与实践中的 C# 内存模型,第 2 部分

    转载自:https://msdn.microsoft.com/zh-cn/magazine/jj883956.aspx 这是介绍 C# 内存模型的系列文章的第二篇(共两篇). 正如在 MSDN 杂志十 ...

  9. php中对共享内存,消息队列的操作

    http://www.cnblogs.com/fengwei/archive/2012/09/12/2682646.html php作为脚本程序,通常生命周期都很短,如在web应用中,一次请求就是ph ...

  10. ###Android 断点调试和高级调试###

    转自:http://www.2cto.com/kf/201506/408358.html 有人说Android 的调试是最坑的,那我只能说是你不会用而已,我可以说Android Studio的调试是我 ...

随机推荐

  1. quarkus依赖注入之十一:拦截器高级特性上篇(属性设置和重复使用)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<quarkus依赖注入> ...

  2. ubuntu20.4操作指令合集

    每个指令前面尽量加上sudo,避免麻烦的权限问题 下载软件:sudo apt install 包名 开启/关闭防火墙(开启/关闭所有端口):sudo ufw enable/disable 防火墙状态: ...

  3. Unity 编辑器资源导入处理函数 OnPreprocessTexture:深入解析与实用案例

    Unity 编辑器资源导入处理函数 OnPreprocessTexture 用法 点击封面跳转下载页面 简介 在Unity中,我们可以使用编辑器资源导入处理函数(OnPreprocessTexture ...

  4. Java读取某个文件夹下的所有文件(支持多级文件夹)

    源码如下: package com.vocy.water.batch; import java.io.FileNotFoundException; import java.io.IOException ...

  5. dedebiz发布文章自动提交到百度搜索的方法

    修改程序文件 依次打开/admin/article_add.php和article_edit.php 找到ClearMyAddon($id, $title); 在其上面加入 //自动提交到百度 els ...

  6. jdk8环境变量

    JAVA_HOME C:\Program Files\Java\jdk1.8.0_333 Path%JAVA_HOME%\bin%JAVA_HOME%\jre\bin CLASSPATH.%JAVA_ ...

  7. Redis系列23:性能优化指南

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  8. “&”控制命令的运行方式

    在Unix.Linux和类Unix系统中,& 符号有特定的意义,用于控制命令的运行方式.具体来说,& 在命令末尾使用时表示将该命令放入后台运行. 前台运行: 如果你在终端输入一个命令, ...

  9. 记录 Ucharts 的使用

    1.开启 2d 渲染 线上运行开启 canvas2d 可以解决图表显示问题 <qiun-data-charts canvas2d .../> canvasId 可以不传,官方内置生成随机字 ...

  10. 掌握Go类型内嵌:设计模式与架构的新视角

    本文深入探讨了Go语言中的类型内嵌特性,从基础概念到实际应用,以及相关的最佳实践.文章不仅讲解了如何在Go中实现和使用类型内嵌,还通过具体的代码示例展示了其应用场景和潜在陷阱.最后,文章总结了类型内嵌 ...