首页 > 系统相关 >聊一聊 .NET高级调试 中的一些内存术语

聊一聊 .NET高级调试 中的一些内存术语

时间:2023-12-04 11:23:24浏览次数:30  
标签:截图 Private 如下 聊一聊 WS 内存 NET pagefile

一:背景

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 观察,截图如下:

三:总结

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

图片名称

标签:截图,Private,如下,聊一聊,WS,内存,NET,pagefile
From: https://www.cnblogs.com/huangxincheng/p/17874509.html

相关文章

  • C#12新功能(.NET 8)有哪些?
    前言作为.NET8发布会的一部分,微软于11月14日发布了C#12的新功能,这也是目前.NET的最新版本。正如之前公布的那样,最显著的改进包括了集合表达式、主构造函数、任何类型的别名以及lambda表达式中参数提供默认值。主构造函数C#12扩展了主构造函数,现在可以在任何class和struct中创......
  • .NET 7(C#)配置使用log4net日志框架的方法
    .NET7(C#)中配置和使用log4net日志框架是一个涉及多步骤的过程。log4net是一个高度灵活且强大的日志记录库,可用于记录应用程序的运行时信息。它支持各种日志输出格式和目的地,如文件、数据库、控制台等。以下是在.NET7(C#)项目中配置和使用log4net的基本步骤:1.安装log4net......
  • go 内存管理
    协程栈go栈的位置1.Go协程栈位于Go-堆内存上2.Go堆内存位于操作系统虚拟内存上go栈的工作流程以main.main为出发点要记录runtime.main的栈基地址记录a和b的局部变量值开辟一个空间记录sum函数的返回值记录b和a的值,这里是为了方便sum在执行时候,......
  • .NET Conf 2023 Chengdu - 成都会场即将到来!
    12月9日天府之国不见不散今年的.NETConf2023,中国区首次有两个会场举办LocalEvent,北京会场12月16日,成都会场12月9日。这是所有中国.NET开发者的节日,成都会场欢迎成渝地区的.NET开发同行积极报名参与哦!活动时间12月9日10:00~17:00,活动地点如下,邀您共同参与。活......
  • C语言-动态内存管理(二)
    第二部分主要是常见的动态内存错误动态内存错误1.对NULL指针的解引用操作对NULL指针的解引用操作,什么意思呢?有些同学写代码的时候比较冲动,如下:intmain(){int*p=(int*)malloc(40);for(inti=0;i<10;++i){*(p+1)=i;}free(p);p=NULL;......
  • CentOS 7.9 安装net 8运行时环境
    1.从官网下载对应的运行时环境压缩包。下载地址:https://dotnet.microsoft.com/zh-cn/download/dotnet/8.02.上传至服务器,以我为例我是上传至/home/dotnet83.运行命令解压环境压缩包tar-zxvf/home/dotnet8/dotnet-runtime-8.0.0-linux-x64.tar.gz-C/home/dotnet84.然后......
  • .net中优秀依赖注入框架Autofac看一篇就够了
    Autofac是一个功能丰富的.NET依赖注入容器,用于管理对象的生命周期、解决依赖关系以及进行属性注入。本文将详细讲解Autofac的使用方法,包括多种不同的注册方式,属性注入,以及如何使用多个 ContainerBuilder 来注册和合并组件。我们将提供详细的源代码示例来说明每个概念。1......
  • .net 下优秀的DI框架推荐,看看你用过几个?
    在.NET生态系统中,有许多出色的依赖注入(DI)框架可供选择。每个框架都有其独特的特点和优点,可以根据项目需求和偏好进行选择。下面详细介绍一些.NET中优秀的DI框架,它们的优点以及适用场景。1、Microsoft.Extensions.DependencyInjection:官方支持:Microsoft.Extensions.DependencyI......
  • .NET8 依赖注入
    依赖注入(DependencyInjection,简称DI)是一种设计模式,用于解耦组件(服务)之间的依赖关系。它通过将依赖关系的创建和管理交给外部容器来实现,而不是在组件(服务)内部直接创建依赖对象。​ 咱就是通过IServiceCollection和IServiceProvider来实现的,他们直接被收入到了runtimelibrari......
  • .net中优秀依赖注入框架Autofac看一篇就够了
     Autofac是一个功能丰富的.NET依赖注入容器,用于管理对象的生命周期、解决依赖关系以及进行属性注入。本文将详细讲解Autofac的使用方法,包括多种不同的注册方式,属性注入,以及如何使用多个 ContainerBuilder 来注册和合并组件。我们将提供详细的源代码示例来说明每个概念......