概述
想必在linux上寫過程式的同學都有分析程式佔用多少記憶體的經歷,或者被問到這樣的問題——你的程式在執行時佔用了多少記憶體(實體記憶體)?通常我們可以透過top命令檢視程式佔用了多少記憶體。這裡我們可以看到VIRT、RES和SHR三個重要的指標,他們分別代表什麼意思呢?這是本文需要跟大家一起探討的問題。當然如果更加深入一點,你可能會問程式所佔用的那些實體記憶體都用在了哪些地方?這時候top命令可能不能給到你你所想要的答案了,不過我們可以分析proc檔案系統提供的smaps檔案,這個檔案詳盡地列出了當前程式所佔用實體記憶體的使用情況。
這篇blog總共分為三個部分。第一部分簡要闡述虛擬記憶體和駐留記憶體這兩個重要的概念;第二部分解釋top命令中VIRT、RES以及SHR三個引數的實際參考意義;最後一部分向大家介紹一下smaps檔案的格式,透過分析smaps檔案我們可以詳細瞭解程式實體記憶體的使用情況,比如mmap檔案佔用了多少空間、動態記憶體開闢消耗了多少空間、函式呼叫棧消耗了多少空間等等。
關於記憶體的兩個概念
要理解top命令關於記憶體使用情況的輸出,我們必須首先搞清楚虛擬記憶體(Virtual Memory)和駐留記憶體(Resident Memory)兩個概念。
【虛擬記憶體】
首先需要強調的是虛擬記憶體不同於實體記憶體,雖然兩者都包含記憶體字眼但是它們屬於兩個不同層面的概念。程式佔用虛擬記憶體空間大並非意味著程式的實體記憶體也一定佔用很大。虛擬記憶體是作業系統核心為了對程式地址空間進行管理(process address space management)而精心設計的一個邏輯意義上的記憶體空間概念。我們程式中的指標其實都是這個虛擬記憶體空間中的地址。比如我們在寫完一段C++程式之後都需要採用g++進行編譯,這時候編譯器採用的地址其實就是虛擬記憶體空間的地址。因為這時候程式還沒有執行,何談實體記憶體空間地址?凡是程式執行過程中可能需要用到的指令或者資料都必須在虛擬記憶體空間中。既然說虛擬記憶體是一個邏輯意義上(假象的)的記憶體空間,為了能夠讓程式在物理機器上執行,那麼必須有一套機制可以讓這些假象的虛擬記憶體空間對映到實體記憶體空間(實實在在的RAM記憶體條上的空間)。這其實就是作業系統中頁對映表(page table)所做的事情了。核心會為系統中每一個程式維護一份相互獨立的頁對映表。。頁對映表的基本原理是將程式執行過程中需要訪問的一段虛擬記憶體空間透過頁對映表對映到一段實體記憶體空間上,這樣CPU訪問對應虛擬記憶體地址的時候就可以透過這種查詢頁對映表的機制訪問實體記憶體上的某個對應的地址。“頁(page)”是虛擬記憶體空間向實體記憶體空間對映的基本單元。
下圖1演示了虛擬記憶體空間和實體記憶體空間的相互關係,它們透過Page Table關聯起來。其中虛擬記憶體空間中著色的部分分別被對映到實體記憶體空間對應相同著色的部分。而虛擬記憶體空間中灰色的部分表示在實體記憶體空間中沒有與之對應的部分,也就是說灰色部分沒有被對映到實體記憶體空間中。這麼做也是本著“按需對映”的指導思想,因為虛擬記憶體空間很大,可能其中很多部分在一次程式執行過程中根本不需要訪問,所以也就沒有必要將虛擬記憶體空間中的這些部分對映到實體記憶體空間上。
到這裡為止已經基本闡述了什麼是虛擬記憶體了。總結一下就是,虛擬記憶體是一個假象的記憶體空間,在程式執行過程中虛擬記憶體空間中需要被訪問的部分會被對映到實體記憶體空間中。虛擬記憶體空間大隻能表示程式執行過程中可訪問的空間比較大,不代表實體記憶體空間佔用也大。