聊一聊 .NET高級調試 中的一些內存術語

一:背景

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 觀察,截圖如下:

三:總結

我盡最大努力通過多個觀察工具用眼見爲實的方式把這幾個內存指標系統的說了一下,希望大家對這幾個術語不再迷茫,以後有人問類似問題就可以把這篇丟過去,減輕了你我負擔...

图片名称
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章