內(nèi)存消耗和泄漏
- 進(jìn)程的VMA
- 進(jìn)程內(nèi)存消耗的4個概念: vss、rss、pss和uss
- page fault的幾種可能性, major 和 minor
- 應(yīng)用內(nèi)存泄漏的解決方法
- 應(yīng)用內(nèi)存泄漏的檢測方法:valgrind 和 addresssanitizer
本節(jié)重點闡述 Linux的應(yīng)用程序究竟消耗了多少內(nèi)存?
一是,看到的內(nèi)存消耗,并不一定是真的消耗。
二是,Linux存在大量的內(nèi)存共享的情況。
動態(tài)鏈接庫的特點:代碼段共享內(nèi)存,數(shù)據(jù)段寫時拷貝。
把一個應(yīng)用程序跑兩個進(jìn)程,這兩個進(jìn)程的代碼段也是共享的。
當(dāng)我們評估進(jìn)程消耗多少內(nèi)存時,就是指在用戶空間消耗的內(nèi)存,即虛擬地址在0~3G的部分,對應(yīng)的物理地址內(nèi)存。內(nèi)核空間的內(nèi)存消耗屬于內(nèi)核,系統(tǒng)調(diào)用申請了很多內(nèi)存,這些內(nèi)存是不屬于進(jìn)程消耗的。
進(jìn)程的虛擬地址空間VMA
task_struct里面有個mm_struct指針, 它代表進(jìn)程的內(nèi)存資源。pgd,代表 頁表的地址; mmap 指向vm_area_struct 鏈表。 vm_area_struct 的每一段代表進(jìn)程的一個虛擬地址空間。vma的每一段,都可能是可執(zhí)行程序的某個數(shù)據(jù)段、某個代碼段,堆、或棧。一個進(jìn)程的虛擬地址,是在0~3G之間任意分布的。
上圖 提供三種方式,看到進(jìn)程的VMA空間。pmap 3474其地址,size, 權(quán)限,通過以上的方式,可以看到進(jìn)程的虛擬地址空間,分布在0~3G,任意一小段一小段分布的。應(yīng)用程序運行起來,就是一堆各種各樣的VMA。VMA對應(yīng)著 堆、棧、代碼段、數(shù)據(jù)段、等,不在任何段里的虛擬地址空間,被認(rèn)為是非法的。
當(dāng)指針訪問地址時,落在一個非法的地址,即不在任何一個VMA區(qū)域。相當(dāng)于訪問一個非法的地址,這些虛擬地址沒有對應(yīng)的物理地址。應(yīng)用程序收到page fault,查看原因,訪問非法位置,返回segv。
在VMA的東西,不等于在內(nèi)存。調(diào)malloc申請了100M內(nèi)存,立馬會多出一個100M的 VMA,代表這段vma區(qū)域有r+w權(quán)限。
應(yīng)用程序訪問內(nèi)存,必須落在一個VMA里。其次,落在一個VMA里也不一定對。把100M的堆申請出來,100M內(nèi)存頁全部映射為0頁。頁表里每一頁寫的只讀,頁表和硬件對應(yīng),MMU只查頁表。而在頁表項中指向物理地址的權(quán)限是只讀,所以在任何時候,去寫其中任何一頁,硬件都會發(fā)生缺頁中斷。
Linux 內(nèi)核在缺頁中斷的處理程序,通過MMU寄存器讀出發(fā)生page fault的地址和原因。發(fā)現(xiàn)此時page fault的原因是寫一個頁表里記錄只讀的物理地址,而vma記錄的虛擬地址又是r+w,此時,linux會申請一頁內(nèi)存。同時把頁表中的權(quán)限改為r+w。
總結(jié):
Linux 內(nèi)核通過VMA管理進(jìn)程每一段虛擬地址空間和權(quán)限。一旦發(fā)生page fault,如果沒有落在任何一個vma區(qū)域,會干掉。VMA的起始地址+size,用來限定程序訪問的地址是否合法。VMA中每一段的權(quán)限,是來界定訪問這段地址是否使用正確的方式訪問。把所有的vma加起來,構(gòu)成進(jìn)程的虛擬地址空間,但這并不代表進(jìn)程真實耗費的內(nèi)存。拿到之后才是真實耗費的內(nèi)存,RSS。耗費的虛擬內(nèi)存,是VSS。
1、申請堆內(nèi)存vma,第一次寫,頁表里的權(quán)限是R ,發(fā)生page fault,linux會去申請一頁內(nèi)存,此時把頁表權(quán)限設(shè)置為 R+W。
2、內(nèi)存訪問落在空白非法區(qū)域,程序收到segv段錯誤。
3、代碼段在VMA記錄是R+X,此時如果對代碼段執(zhí)行寫,程序會收到segv段錯誤。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【865977150】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦??!
內(nèi)核學(xué)習(xí)網(wǎng)站:
Linux內(nèi)核源碼/內(nèi)存調(diào)優(yōu)/文件系統(tǒng)/進(jìn)程管理/設(shè)備驅(qū)動/網(wǎng)絡(luò)協(xié)議棧-學(xué)習(xí)視頻教程-騰訊課堂?ke.qq.com/course/4032547?flowToken=1040236
minor 和major 缺頁
缺頁,分為兩種情況:主缺頁 和次缺頁。
主缺頁 和次缺頁,區(qū)別就是 申請內(nèi)存時,是否需要讀硬盤。前者需要。
如上圖第4種情況,在代碼段里執(zhí)行時,出現(xiàn)缺頁。linux申請一頁內(nèi)存,而且要從硬盤中讀取代碼段的內(nèi)容,此時產(chǎn)生了IO,稱為 major缺頁。
無論是代碼段還是堆,都是邊執(zhí)行邊產(chǎn)生缺頁中斷,申請實際的內(nèi)存給代碼段,且從硬盤中讀取代碼段的內(nèi)容到內(nèi)存。這個過程時間比較長。
minor: malloc的內(nèi)存,產(chǎn)生缺頁中斷。去申請一頁內(nèi)存,沒有產(chǎn)生IO的行為。major缺頁處理時間,遠(yuǎn)大于minor。
vss、rss、pss和uss的區(qū)別
VSS - Virtual Set Size
RSS - Resident Set Size
PSS - Proportional Set Size
USS - Unique Set Size
ASAN - AddressSanitizer
LSAN - LeakSanitizer
如上圖,中間是一根內(nèi)存條。三個進(jìn)程分別是1044,1045,1054, 每一個進(jìn)程對應(yīng)一個page table,頁表項記錄虛擬地址如何往物理地址轉(zhuǎn)換。硬件里的寄存器,記錄頁表的物理地址。當(dāng)linux做進(jìn)程上下文切換時,頁表也跟著一起切換。
三個進(jìn)程都需要使用libc的代碼段:
VSS = 1 +2 +3
RSS = 4 +5 +6
PSS= 4/3 + 5/2 + 6 比例化的
USS= 6 獨占且駐留的
工具:smem ,查看進(jìn)程使用內(nèi)存的情況。
一般來講,進(jìn)程使用的內(nèi)存量,還是看PSS,強調(diào)公平性??磧?nèi)存泄漏看USS 就好了。
內(nèi)存泄漏 界定和檢測方法
界定:連續(xù)多點采樣法,隨著時間越久,進(jìn)程耗費內(nèi)存越多。主要由內(nèi)存申請和釋放不是成對引起。RSS/USS曲線,觀察方法:使用smem工具查看多次進(jìn)程使用內(nèi)存,USS使用量。
檢查工具:
1、valgrind ,會跑一個虛擬機,運行時檢查進(jìn)程的內(nèi)存行為。會放慢程序的速度。不需要重新編譯程序。
2、addressanitizer,需要重新編譯程序。編譯時加參數(shù),-fsanitize
gcc 4.9才支持,只會放慢程序速度2~3倍。
-
Linux
+關(guān)注
關(guān)注
87文章
11161瀏覽量
208460 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3221瀏覽量
57499 -
內(nèi)存泄漏
+關(guān)注
關(guān)注
0文章
39瀏覽量
9190
發(fā)布評論請先 登錄
相關(guān)推薦
評論