一:背景 1. 講故事 在高級調試的旅程中,經常會有一些朋友問我什麼是 工作集(記憶體),什麼是 提交大小,什麼是 Virtual Size, 什麼是 Working Set 。。。截圖如下: 既然有很多朋友問,這些用口頭也不怎麼好描述,剛好上午有時間就系統的聊一下吧。 二:記憶體術語解讀 1. Vir ...
一:背景
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 Shareable
和 WS Shared
到底有什麼區別,從字面意思上看就是:一個可被多個進程共用的記憶體頁集合中,當前已經被共用的記憶體頁集合。
可能這麼說大家有點懵逼,不過沒關係,可以藉助 VMMap 工具觀察。
- 開啟一個 ConsoleApp6 進程觀察
從圖中可以看到 Shareable=104k
,而 Shared=0k
,這是什麼意思呢? 由於 ConsoleApp6.exe 是文件映射到記憶體的,占用了 104k 的物理記憶體,此時沒有其他進程共用這一塊物理記憶體,所以此時為Shared=0,要想把這裡的 Shared 也給填充起來,最簡單的辦法就是開啟多個ConsoleApp6實例。
- 開啟多個 ConsoleApp6 進程觀察
接下來反覆點擊 ConsoleApp6 生成多個實例,再次使用 VMMap 觀察,截圖如下:
三:總結
我盡最大努力通過多個觀察工具用眼見為實的方式把這幾個記憶體指標系統的說了一下,希望大家對這幾個術語不再迷茫,以後有人問類似問題就可以把這篇丟過去,減輕了你我負擔...