由於技術能力有限,文章僅能進行簡要分析和說明,如有不對的地方,請指正,謝謝?。
1 RAMMap和PoolMon工具簡介
RAMMap和PoolMon都是微軟Sysinternals的工具,前者可以從使用型別、頁列表、程式、檔案、優先順序,以及實體地址來檢查記憶體的使用情況,但是無法檢查尚未提交和分頁的程式記憶體使用情況;後者可以是作為RAMMap的補充,可以檢查系統分頁和非分頁的緩衝池記憶體使用情況,並且提供了按照驅動程式的角度來檢視其記憶體使用情況。
可以說RAMMap可以詳細分析使用者模式下程式的記憶體分配情況,但對於核心模式下的記憶體分配,還是要使用PoolMon來詳細分析。
關於RAMMap的微軟介紹:RAMMap - Sysinternals | Microsoft Learn
關於PoolMon的微軟介紹:PoolMon - Windows drivers | Microsoft Learn
2 Windows記憶體分配說明
Windows作業系統使用頁來分配和管理記憶體,並將多個實體記憶體頁組成一片虛擬地址空間,實體記憶體頁是不連續的,而虛擬地址空間是連續的。應用程式正是使用了一片連續的虛擬地址來訪問實體記憶體中不連續的記憶體頁,並且由處理器完成虛擬地址和實體地址之間的轉換。
處理器根據不同的應用程式程式碼在使用者模式和核心模式些切換,使用者模式執行的是notepad.exe、calc.exe這類應用程式,每個應用程式的虛擬地址空間都是獨立的,稱為“使用者空間”,如果一個應用程式發生故障,其他應用程式和作業系統不受崩潰的影響;核心模式包含了核心系統元件和驅動程式,所有程式碼共享單個虛擬地址空間,稱為“系統空間”,如果核心模式驅動程式發生故障,整個作業系統就會發生故障。
而在系統空間裡面,又有兩個可以動態分配記憶體的區域:分頁緩衝池和非分頁緩衝池,分頁緩衝池的記憶體可以被調出到磁碟(發生swap),但是非分頁緩衝池的區域是無法調出到磁碟(無法swap)一直佔用著記憶體。
核心模式下的核心繫統元件或者驅動程式可以同時使用分頁緩衝池和非分頁緩衝池的空間,記住如果使用了對於非分頁緩衝區,則是固定在實體記憶體中,無法swap的。
3 案例分享
有一臺Windows Server 2016的伺服器,執行在VMware vSphere虛擬化平臺上,平臺版本為6.7,每間隔1周左右,虛擬機器就會出現記憶體異常增長,且透過作業系統自帶的工作管理員、資源管理器均無法找到消耗記憶體的具體程式資訊,並且也使用了防毒軟體進行掃描,沒有發現異常程式。
- 虛擬化平臺監控到記憶體異常增長。
- 工作管理員顯示消耗最大記憶體空間的為dwm.exe程式,實際上才佔用134252KB。
- 防毒軟體掃描結果,沒有發現任何異常資訊。
3.1 使用RAMMap分析記憶體的整體分配情況
RAMMap不需要額外安裝,在RAMMap - Sysinternals | Microsoft Learn下載傳到伺服器上執行即可。
- 解壓後在資料夾中找到RAMMap64(64位作業系統),雙擊開啟。
- 發現99%的記憶體都被分配到了NonPaged Pool
結合前文對Windows記憶體的分配說明,Nonpaged Pool是屬於核心模式下的系統空間,這篇區域的記憶體基本被作業系統的核心元件和驅動程式所使用,而那就需要使用PoolMon繼續分析Nonpaged Pool的具體使用情況。
3.2 使用PoolMon分析非分頁緩衝池的使用情況
PoolMon包含在Windows 驅動程式工具包 (WDK) 的 \Tools\Other 子目錄中,微軟並沒有提供單獨的工具下載,而WDK工具的安裝需要聯網,伺服器又處於內網環境無法訪問網際網路。後面經過測試,可以找一臺可聯網的機器安裝WDK工具,在WDK安裝目錄下的\Tools\x64 子目錄找到poolmon.exe複製出來,例如我安裝到了C:\Program Files (x86)\Windows Kits\10\Tools\x64
目錄下。
接下來就是使用PoolMon分析非分頁緩衝池的詳細使用情況了:
- 開啟cmd,在poolmon.exe所在目錄,直接執行
.\poolmon.exe -p -b
,可以看到消耗最多記憶體空間是VFil和VNet。(這裡因為顯示不全,暫不) - 檢查作業系統補丁情況,發現只有安裝作業系統時自帶的補丁,未再安裝其它更新。
- 檢查虛擬化平臺的BUG情況,暫未發現直接關聯的,但是在一篇KB(https://kb.vmware.com/s/article/2077302)中找到了關聯的問題,VFil和VNet可能是VMware Tools的驅動,並且要求升級VMware Tools到10.0.8以上,而虛擬機器所安裝的VMware Tools版本是12.0.0,故基本可以排除是這個BUG。
我們已經透過PoolMon定位到消耗記憶體資源的罪魁禍首是vFIL和vNET,由於VMware Tools的版本比KB中說明的版本要高,暫不考慮升級VMware Tools。
由於該問題是可復現的(基本上執行了一週左右就會出現這個情況),溝通處理該問題的解決方案時,採用了排除法:
- 考慮先對作業系統安裝最新的補丁。
- 如果作業系統補丁無效,則說明不是由於作業系統自身原因,再考慮升級VMware Tools。
最後透過觀察,確認是安裝了當時作業系統最新的補丁後解決了這個問題。
總結:工欲利其事,必先利其器。需要對所解決的事情涉及的理論和內容有一定的瞭解,才能夠正確地使用工具來解決問題。