觀察進程的內存佔用狀況

實際和以前的free命令是有點相似的。 不過free更專一應用,這個更專一理解。node

 

概述

      想必在linux上寫過程序的同窗都有分析進程佔用多少內存的經歷,或者被問到這樣的問題——你的程序在運行時佔用了多少內存(物理內存)?一般咱們能夠經過top命令查看進程佔用了多少內存。這裏咱們能夠看到VIRT、RES和SHR三個重要的指標,他們分別表明什麼意思呢?這是本文須要跟你們一塊兒探討的問題。固然若是更加深刻一點,你可能會問進程所佔用的那些物理內存都用在了哪些地方?這時候top命令可能不能給到你你所想要的答案了,不過咱們能夠分析proc文件系統提供的smaps文件,這個文件詳盡地列出了當前進程所佔用物理內存的使用狀況。linux

     這篇blog總共分爲三個部分。第一部分簡要闡述虛擬內存和駐留內存這兩個重要的概念;第二部分解釋top命令中VIRT、RES以及SHR三個參數的實際參考意義;最後一部分向你們介紹一下smaps文件的格式,經過分析smaps文件咱們能夠詳細瞭解進程物理內存的使用狀況,好比mmap文件佔用了多少空間、動態內存開闢消耗了多少空間、函數調用棧消耗了多少空間等等。ide

關於內存的兩個概念

      要理解top命令關於內存使用狀況的輸出,咱們必須首先搞清楚虛擬內存(Virtual Memory)和駐留內存(Resident Memory)兩個概念。函數

  • 虛擬內存

   首先須要強調的是虛擬內存不一樣於物理內存,雖然二者都包含內存字眼可是它們屬於兩個不一樣層面的概念。進程佔用虛擬內存空間大並不是意味着程序的物理內存也必定佔用很大。虛擬內存是操做系統內核爲了對進程地址空間進行管理(process address space management)而精心設計的一個邏輯意義上的內存空間概念。咱們程序中的指針其實都是這個虛擬內存空間中的地址。好比咱們在寫完一段C++程序以後都須要採用g++進行編譯,這時候編譯器採用的地址其實就是虛擬內存空間的地址。由於這時候程序尚未運行,何談物理內存空間地址?凡是程序運行過程當中可能須要用到的指令或者數據都必須在虛擬內存空間中。既然說虛擬內存是一個邏輯意義上(假象的)的內存空間,爲了可以讓程序在物理機器上運行,那麼必須有一套機制可讓這些假象的虛擬內存空間映射到物理內存空間(實實在在的RAM內存條上的空間)。這其實就是操做系統中頁映射表(page table)所作的事情了。內核會爲系統中每個進程維護一份相互獨立的頁映射表。。頁映射表的基本原理是將程序運行過程當中須要訪問的一段虛擬內存空間經過頁映射表映射到一段物理內存空間上,這樣CPU訪問對應虛擬內存地址的時候就能夠經過這種查找頁映射表的機制訪問物理內存上的某個對應的地址。「頁(page)」是虛擬內存空間向物理內存空間映射的基本單元。post

        下圖1演示了虛擬內存空間和物理內存空間的相互關係,它們經過Page Table關聯起來。其中虛擬內存空間中着色的部分分別被映射到物理內存空間對應相同着色的部分。而虛擬內存空間中灰色的部分表示在物理內存空間中沒有與之對應的部分,也就是說灰色部分沒有被映射到物理內存空間中。這麼作也是本着「按需映射」的指導思想,由於虛擬內存空間很大,可能其中不少部分在一次程序運行過程當中根本不須要訪問,因此也就沒有必要將虛擬內存空間中的這些部分映射到物理內存空間上。性能

         到這裏爲止已經基本闡述了什麼是虛擬內存了。總結一下就是,虛擬內存是一個假象的內存空間,在程序運行過程當中虛擬內存空間中須要被訪問的部分會被映射到物理內存空間中。虛擬內存空間大隻能表示程序運行過程當中可訪問的空間比較大,不表明物理內存空間佔用也大。優化

 

                   圖1. 虛擬內存空間到物理內存空間映射spa

  • 駐留內存

  駐留內存,顧名思義是指那些被映射到進程虛擬內存空間的物理內存。上圖1中,在系統物理內存空間中被着色的部分都是駐留內存。好比,A一、A二、A3和A4是進程A的駐留內存;B一、B2和B3是進程B的駐留內存。進程的駐留內存就是進程實實在在佔用的物理內存。通常咱們所講的進程佔用了多少內存,其實就是說的佔用了多少駐留內存而不是多少虛擬內存。由於虛擬內存大並不意味着佔用的物理內存大。操作系統

  關於虛擬內存和駐留內存這兩個概念咱們說到這裏。下面一部分咱們來看看top命令中VIRT、RES和SHR分別表明什麼意思。設計

top命令中VIRT、RES和SHR的含義

      搞清楚了虛擬內存的概念以後解釋VIRT的含義就很簡單了。VIRT表示的是進程虛擬內存空間大小。對應到圖1中的進程A來講就是A一、A二、A三、A4以及灰色部分全部空間的總和。也就是說VIRT包含了在已經映射到物理內存空間的部分和還沒有映射到物理內存空間的部分總和。

  RES的含義是指進程虛擬內存空間中已經映射到物理內存空間的那部分的大小。對應到圖1中的進程A來講就是A一、A二、A3以及A4幾個部分空間的總和。因此說,看進程在運行過程當中佔用了多少內存應該看RES的值而不是VIRT的值。

  最後來看看SHR所表示的含義。SHR是share(共享)的縮寫,它表示的是進程佔用的共享內存大小。在上圖1中咱們看到進程A虛擬內存空間中的A4和進程B虛擬內存空間中的B3都映射到了物理內存空間的A4/B3部分。咋一看很奇怪。爲何會出現這樣的狀況呢?其實咱們寫的程序會依賴於不少外部的動態庫(.so),好比libc.so、libld.so等等。這些動態庫在內存中僅僅會保存/映射一份,若是某個進程運行時須要這個動態庫,那麼動態加載器會將這塊內存映射到對應進程的虛擬內存空間中。多個進展之間經過共享內存的方式相互通訊也會出現這樣的狀況。這麼一來,就會出現不一樣進程的虛擬內存空間會映射到相同的物理內存空間。這部分物理內存空間實際上是被多個進程所共享的,因此咱們將他們稱爲共享內存,用SHR來表示。某個進程佔用的內存除了和別的進程共享的內存以外就是本身的獨佔內存了。因此要計算進程獨佔內存的大小隻要用RES的值減去SHR值便可。 

進程的smaps文件

  經過top命令咱們已經能看出進程的虛擬空間大小(VIRT)、佔用的物理內存(RES)以及和其餘進程共享的內存(SHR)。可是僅此而已,若是我想知道以下問題:

  1. 進程的虛擬內存空間的分佈狀況,好比heap佔用了多少空間、文件映射(mmap)佔用了多少空間、stack佔用了多少空間?
  2. 進程是否有被交換到swap空間的內存,若是有,被交換出去的大小?
  3. mmap方式打開的數據文件有多少頁在內存中是髒頁(dirty page)沒有被寫回到磁盤的?
  4. mmap方式打開的數據文件當前有多少頁面已經在內存中,有多少頁面還在磁盤中沒有加載到page cahe中?
  5. 等等

  以上這些問題都沒法經過top命令給出答案,可是有時候這些問題正是咱們在對程序進行性能瓶頸分析和優化時所須要回答的問題。所幸的是,世界上解決問題的方法總比問題自己要多得多。linux經過proc文件系統爲每一個進程都提供了一個smaps文件,經過分析該文件咱們就能夠一一回答以上提出的問題。

  在smaps文件中,每一條記錄(以下圖2所示)表示進程虛擬內存空間中一塊連續的區域。其中第一行從左到右依次表示地址範圍、權限標識、映射文件偏移、設備號、inode、文件路徑。詳細解釋能夠參見understanding-linux-proc-id-maps

  接下來8個字段的含義分別以下:

  • Size:表示該映射區域在虛擬內存空間中的大小。
  • Rss:表示該映射區域當前在物理內存中佔用了多少空間      
  • Shared_Clean:和其餘進程共享的未被改寫的page的大小
  • Shared_Dirty: 和其餘進程共享的被改寫的page的大小
  • Private_Clean:未被改寫的私有頁面的大小。
  • Private_Dirty: 已被改寫的私有頁面的大小。
  • Swap:表示非mmap內存(也叫anonymous memory,好比malloc動態分配出來的內存)因爲物理內存不足被swap到交換空間的大小。
  • Pss:該虛擬內存區域平攤計算後使用的物理內存大小(有些內存會和其餘進程共享,例如mmap進來的)。好比該區域所映射的物理內存部分同時也被另外一個進程映射了,且該部分物理內存的大小爲1000KB,那麼該進程分攤其中一半的內存,即Pss=500KB。

 

                             圖2. smaps文件中的一條記錄

  有了smap如此詳細關於虛擬內存空間到物理內存空間的映射信息,相信你們已經可以經過分析該文件回答上面提出的4個問題。

   最後但願全部讀者可以經過閱讀本文對進程的虛擬內存和物理內存有一個更加清晰認識,並能更加準確理解top命令關於內存的輸出,最後能夠經過smaps文件更進一步分析進程使用內存的狀況。

相關文章
相關標籤/搜索