理解virt、res、shr之間的關(guān)系(linux系統(tǒng)篇)
前言
想必在linux上寫過程序的同學(xué)都有分析進程占用多少內(nèi)存的經(jīng)歷,或者被問到這樣的問題——你的程序在運行時占用了多少內(nèi)存(物理內(nèi)存)?
通常我們可以通過top命令查看進程占用了多少內(nèi)存。這里我們可以看到VIRT、RES和SHR三個重要的指標(biāo),他們分別代表什么意思呢?
這是本文需要跟大家一起探討的問題。當(dāng)然如果更加深入一點,你可能會問進程所占用的那些物理內(nèi)存都用在了哪些地方?這時候top命令可能不能給到你你所想要的答案了,不過我們可以分析proc文件系統(tǒng)提供的smaps文件,這篇文章詳盡地列出了當(dāng)前進程所占用物理內(nèi)存的使用情況。
本文將分為三個部分:
1、分簡要闡述虛擬內(nèi)存和駐留內(nèi)存這兩個重要的概念;
2、解釋top命令中VIRT、RES以及SHR三個參數(shù)的實際參考意義;
3、向大家介紹一下smaps文件的格式,通過分析smaps文件我們可以詳細了解進程物理內(nèi)存的使用情況,比如mmap文件占用了多少空間、動態(tài)內(nèi)存開辟消耗了多少空間、函數(shù)調(diào)用棧消耗了多少空間等等。
01關(guān)于內(nèi)存的兩個概念
要理解top命令關(guān)于內(nèi)存使用情況的輸出,我們必須首先搞清楚虛擬內(nèi)存(Virtual Memory)和駐留內(nèi)存(Resident Memory)兩個概念。
(1)虛擬內(nèi)存
首先需要強調(diào)的是虛擬內(nèi)存不同于物理內(nèi)存,雖然兩者都包含內(nèi)存字眼但是它們屬于兩個不同層面的概念。進程占用虛擬內(nèi)存空間大并非意味著程序的物理內(nèi)存也一定占用很大。虛擬內(nèi)存是操作系統(tǒng)內(nèi)核為了對進程地址空間進行管理(process address space management)而精心設(shè)計的一個邏輯意義上的內(nèi)存空間概念。
我們程序中的指針其實都是這個虛擬內(nèi)存空間中的地址。比如我們在寫完一段C++程序之后都需要采用g++進行編譯,這時候編譯器采用的地址其實就是虛擬內(nèi)存空間的地址。因為這時候程序還沒有運行,何談物理內(nèi)存空間地址?凡是程序運行過程中可能需要用到的指令或者數(shù)據(jù)都必須在虛擬內(nèi)存空間中。
既然說虛擬內(nèi)存是一個邏輯意義上(假象的)的內(nèi)存空間,為了能夠讓程序在物理機器上運行,那么必須有一套機制可以讓這些假象的虛擬內(nèi)存空間映射到物理內(nèi)存空間(實實在在的RAM內(nèi)存條上的空間)。這其實就是操作系統(tǒng)中頁映射表(page table)所做的事情了。
內(nèi)核會為系統(tǒng)中每一個進程維護一份相互獨立的頁映射表。頁映射表的基本原理是將程序運行過程中需要訪問的一段虛擬內(nèi)存空間通過頁映射表映射到一段物理內(nèi)存空間上,這樣CPU訪問對應(yīng)虛擬內(nèi)存地址的時候就可以通過這種查找頁映射表的機制訪問物理內(nèi)存上的某個對應(yīng)的地址。“頁(page)”是虛擬內(nèi)存空間向物理內(nèi)存空間映射的基本單元。
下圖演示了虛擬內(nèi)存空間和物理內(nèi)存空間的相互關(guān)系,它們通過Page Table關(guān)聯(lián)起來。其中虛擬內(nèi)存空間中著色的部分分別被映射到物理內(nèi)存空間對應(yīng)相同著色的部分。而虛擬內(nèi)存空間中灰色的部分表示在物理內(nèi)存空間中沒有與之對應(yīng)的部分,也就是說灰色部分沒有被映射到物理內(nèi)存空間中。這么做也是本著“按需映射”的指導(dǎo)思想,因為虛擬內(nèi)存空間很大,可能其中很多部分在一次程序運行過程中根本不需要訪問,所以也就沒有必要將虛擬內(nèi)存空間中的這些部分映射到物理內(nèi)存空間上。
虛擬內(nèi)存空間到物理內(nèi)存空間映射
到這里為止已經(jīng)基本闡述了什么是虛擬內(nèi)存了。
總結(jié)一下就是,虛擬內(nèi)存是一個假象的內(nèi)存空間,在程序運行過程中虛擬內(nèi)存空間中需要被訪問的部分會被映射到物理內(nèi)存空間中。虛擬內(nèi)存空間大只能表示程序運行過程中可訪問的空間比較大,不代表物理內(nèi)存空間占用也大。
(2)駐留內(nèi)存
駐留內(nèi)存,顧名思義是指那些被映射到進程虛擬內(nèi)存空間的物理內(nèi)存。上圖中,在系統(tǒng)物理內(nèi)存空間中被著色的部分都是駐留內(nèi)存。比如,A1、A2、A3和A4是進程A的駐留內(nèi)存;B1、B2和B3是進程B的駐留內(nèi)存。
進程的駐留內(nèi)存就是進程實實在在占用的物理內(nèi)存。一般我們所講的進程占用了多少內(nèi)存,其實就是說的占用了多少駐留內(nèi)存而不是多少虛擬內(nèi)存。因為虛擬內(nèi)存大并不意味著占用的物理內(nèi)存大。
02top命令中VIRT、RES和SHR
關(guān)于虛擬內(nèi)存和駐留內(nèi)存這兩個概念我們說到這里。下面一部分我們來看看top命令中VIRT、RES和SHR分別代表什么意思。
top命令中VIRT、RES和SHR的含義
搞清楚了虛擬內(nèi)存的概念之后解釋VIRT的含義就很簡單了。VIRT表示的是進程虛擬內(nèi)存空間大小。對應(yīng)到圖1中的進程A來說就是A1、A2、A3、A4以及灰色部分所有空間的總和。也就是說VIRT包含了在已經(jīng)映射到物理內(nèi)存空間的部分和尚未映射到物理內(nèi)存空間的部分總和。
RES的含義是指進程虛擬內(nèi)存空間中已經(jīng)映射到物理內(nèi)存空間的那部分的大小。對應(yīng)到圖1中的進程A來說就是A1、A2、A3以及A4幾個部分空間的總和。所以說,看進程在運行過程中占用了多少內(nèi)存應(yīng)該看RES的值而不是VIRT的值。
最后來看看SHR所表示的含義。
SHR是share(共享)的縮寫,它表示的是進程占用的共享內(nèi)存大小。在上圖中我們看到進程A虛擬內(nèi)存空間中的A4和進程B虛擬內(nèi)存空間中的B3都映射到了物理內(nèi)存空間的A4/B3部分。咋一看很奇怪。
為什么會出現(xiàn)這樣的情況呢?
其實我們寫的程序會依賴于很多外部的動態(tài)庫(.so),比如libc.so、libld.so等等。這些動態(tài)庫在內(nèi)存中僅僅會保存/映射一份,如果某個進程運行時需要這個動態(tài)庫,那么動態(tài)加載器會將這塊內(nèi)存映射到對應(yīng)進程的虛擬內(nèi)存空間中。多個進展之間通過共享內(nèi)存的方式相互通信也會出現(xiàn)這樣的情況。
這么一來,就會出現(xiàn)不同進程的虛擬內(nèi)存空間會映射到相同的物理內(nèi)存空間。這部分物理內(nèi)存空間其實是被多個進程所共享的,所以我們將他們稱為共享內(nèi)存,用SHR來表示。
某個進程占用的內(nèi)存除了和別的進程共享的內(nèi)存之外就是自己的獨占內(nèi)存了。所以要計算進程獨占內(nèi)存的大小只要用RES的值減去SHR值即可。
03進程的smaps文件
通過top命令我們已經(jīng)能看出進程的虛擬空間大?。╒IRT)、占用的物理內(nèi)存(RES)以及和其他進程共享的內(nèi)存(SHR)。但是僅此而已,如果我想知道如下問題:
進程的虛擬內(nèi)存空間的分布情況,比如heap占用了多少空間、文件映射(mmap)占用了多少空間、stack占用了多少空間?
進程是否有被交換到swap空間的內(nèi)存,如果有,被交換出去的大小?
mmap方式打開的數(shù)據(jù)文件有多少頁在內(nèi)存中是臟頁(dirty page)沒有被寫回到磁盤的?
mmap方式打開的數(shù)據(jù)文件當(dāng)前有多少頁面已經(jīng)在內(nèi)存中,有多少頁面還在磁盤中沒有加載到page cahe中?
等等
以上這些問題都無法通過top命令給出答案,但是有時候這些問題正是我們在對程序進行性能瓶頸分析和優(yōu)化時所需要回答的問題。所幸的是,世界上解決問題的方法總比問題本身要多得多。linux通過proc文件系統(tǒng)為每個進程都提供了一個smaps文件,通過分析該文件我們就可以一一回答以上提出的問題。
在smaps文件中,每一條記錄(如下圖所示)表示進程虛擬內(nèi)存空間中一塊連續(xù)的區(qū)域。其中第一行從左到右依次表示地址范圍、權(quán)限標(biāo)識、映射文件偏移、設(shè)備號、inode、文件路徑。詳細解釋可以參見understanding-linux-proc-id-maps。
接下來8個字段的含義分別如下:
? Size:表示該映射區(qū)域在虛擬內(nèi)存空間中的大小。
?Rss:表示該映射區(qū)域當(dāng)前在物理內(nèi)存中占用了多少空間
?Shared_Clean:和其他進程共享的未被改寫的page的大小
?Shared_Dirty:和其他進程共享的被改寫的page的大小
?Private_Clean:未被改寫的私有頁面的大小。
?Private_Dirty:已被改寫的私有頁面的大小。
?Swap:表示非mmap內(nèi)存(也叫anonymous memory,比如malloc動態(tài)分配出來的內(nèi)存)由于物理內(nèi)存不足被swap到交換空間的大小。
?Pss:該虛擬內(nèi)存區(qū)域平攤計算后使用的物理內(nèi)存大小(有些內(nèi)存會和其他進程共享,例如mmap進來的)。比如該區(qū)域所映射的物理內(nèi)存部分同時也被另一個進程映射了,且該部分物理內(nèi)存的大小為1000KB,那么該進程分攤其中一半的內(nèi)存,即Pss=500KB。
smaps文件中的一條記錄
有了smap如此詳細關(guān)于虛擬內(nèi)存空間到物理內(nèi)存空間的映射信息,相信大家已經(jīng)能夠通過分析該文件回答上面提出的4個問題。
04最后希望大家能夠通過閱讀本文對進程的虛擬內(nèi)存和物理內(nèi)存有一個更加清晰認識,并能更加準(zhǔn)確理解top命令關(guān)于內(nèi)存的輸出,最后可以通過smaps文件更進一步分析進程使用內(nèi)存的情況。
-
Linux
+關(guān)注
關(guān)注
87文章
11123瀏覽量
207921 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
2903瀏覽量
73546 -
Virt
+關(guān)注
關(guān)注
0文章
2瀏覽量
6931
原文標(biāo)題:理解virt、res、shr之間的關(guān)系(linux系統(tǒng)篇)
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論