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