在產品的開發中,通過對當前系統消耗記憶體總量的統計,可以對產品所需記憶體總量進行精確的評估,從而選擇合適的記憶體晶元與大小,降低產品的成本。在遇到記憶體洩露類問題時,經常會對此束手無策,本文通過對proc下程序相關的檔案進行分析,精確評估系統消耗記憶體的大小,還可以對記憶體洩露類問題的解決提供一種定位手段。
linux在記憶體使用上的原則是:如果記憶體充足,不用白不用,盡量使用記憶體來快取一些檔案,從而加快程序的執行速度,而當記憶體不足時,會通過相應的記憶體**策略收回cache記憶體,供程序使用。
一、系統總記憶體的分析
可以從proc目錄下的meminfo檔案了解到當前系統記憶體的使用情況彙總,其中可用的物理記憶體=memfree+buffers+cached,當memfree不夠時,核心會通過回寫機制(pdflush執行緒)把cached和buffered記憶體回寫到後備儲存器,從而釋放相關記憶體供程序使用,或者通過手動方式顯式釋放cache記憶體:
echo 3 > /proc/sys/vm/drop_caches下圖是海思平台下當前系統記憶體的總體使用情況,其中可以看到,系統消耗掉了29m的記憶體,下面繼續分析這些記憶體都是被誰消耗掉了。
# cat /proc/meminfo
memtotal: 68956 kb memfree: 18632 kb
buffers: 4096 kb
cached: 17260 kb
swapcached: 0 kb
active: 21304 kb
inactive: 19248 kb
swaptotal: 0 kb
swapfree: 0 kb
dirty: 0 kb
writeback: 0 kb
anonpages: 19216 kb
slab: 6900 kb
sreclaimable: 924 kb
sunreclaim: 5976 kb
pagetables: 460 kb
nfs_unstable: 0 kb
bounce: 0 kb
commitlimit: 62060 kb
committed_as: 28864 kb
vmalloctotal: 442368 kb
vmallocused: 46984 kb
vmallocchunk: 393212 kb
二、程序使用記憶體的統計
在32位作業系統中,每個程序擁有4g的虛擬記憶體空間,其中0~3gb是每個程序的私有使用者空間,這個空間對系統中其他程序是不可見的。3~4gb是linux核心空間,由系統所有的程序以及核心所共享的。通過訪問/proc//下相關檔案,可以了解每個執行緒虛擬記憶體空間的使用情況,從而了解每個執行緒所消耗記憶體的多少。
由於我們的產品都是使用多執行緒方式實現的,多個執行緒共享乙個程序的使用者態虛擬位址空間,虛擬位址空間包含若干區域,主要有如下幾個區域:
1、當前執行檔案的**段,該**段稱為text段。
2、執行檔案的資料段,主要儲存執行檔案用到的全域性變數,靜態變數。
3、儲存全域性變數和動態產生的資料的堆。
4、用於儲存區域性變數和實現函式呼叫的棧。
5、採用mmap方式對映到虛擬位址空間中的記憶體段
所以只需要檢視任意乙個執行緒的使用者態虛擬位址空間分配即可知道屬於同一程序的所有執行緒占用總記憶體的大小。可以通過檢視/proc//maps檔案來獲取相關的虛擬位址空間內容,下文摘列部分典型的內容:
# cat /proc/568/maps
00008000-0036a000 r-xp 00000000 00:0e 236 /home/hik/hicore 00372000-003a5000 rw-p 00362000 00:0e 236 /home/hik/hicore
003a5000-00e28000 rwxp 003a5000 00:00 0 [heap]
40000000-40005000 r-xp 00000000 01:00 94 /lib/ld-uclibc.so.0
416db000-41770000 rw-s c2005000 00:0f 68 /dev/mem
b51fc000-b5200000 rwxp b51fc000 00:00 0
…….be1fc000-be200000 rwxp be1fc000 00:00 0
be93b000-be950000 rwxp befeb000 00:00 0 [stack]
第一行:從r-xp可知其許可權為唯讀、可執行,該段記憶體位址對應於執行檔案的**段,程式的**段需載入到記憶體中才可以執行。由於其唯讀,不會被修改,所以在整個系統內共享。
第二行:從rw-p可知其許可權為可讀寫,不可執行,該段記憶體位址對應於執行檔案的資料段,存放執行檔案所用到的全域性變數、靜態變數。
第三行:從rwxp可知其許可權是可讀寫,可執行,位址空間向上增長,而且不對應檔案,是堆段,程序使用malloc申請的記憶體放在堆段。每個程序只有乙個堆段,不論是主程序,還是不同的執行緒申請的記憶體,都反映到到程序的堆段。堆段向上增長,最大可以增長到1gb的位置,即0x40000000,如果大於1gb,glibc將採用mmap的方式,為堆申請一塊記憶體。
第四行:是程式連線的共享庫的記憶體位址。
第五行:是以mmap方式對映的虛擬位址空間。
第六、七行:是執行緒的棧區位址段,每個執行緒的棧大小都是16k。
第八行:是程序的棧區。關於棧段,每個執行緒都有乙個,如果程序中有多個執行緒,則包含多個棧段。
三、當前系統總記憶體的統計
1、程序占用的總記憶體可以通過上述maps表計算出來。
2、當系統執行起來以後,會把應用層相關的檔案掛載到tmpfs檔案系統下,海思系統下這部分大概有13m左右,這部分記憶體是以cache方式統計出來的,但是這部分記憶體cache無法通過**策略或者顯式的呼叫釋放掉。
3、根檔案系統ramdisk占用的記憶體。
4、當前系統保留記憶體的大小,可以通過檢視/proc/sys/vm/min_free_kbytes來獲取或者修改此記憶體的大小。
5、當然,當系統執行起來後,還應該留有一定的記憶體用於在硬碟讀寫時做cache或者網路負荷比較高時分配skb等,一般需要30m以上。
四、對除錯記憶體洩露類問題的一些啟示
當程序申請記憶體時,實際上是glibc中內建的記憶體管理器接收了該請求,隨著程序申請記憶體的增加,記憶體管理器會通過系統呼叫陷入核心,從而為程序分配更多的記憶體。
針對堆段的管理,核心提供了兩個系統呼叫brk和mmap,brk用於更改堆頂位址,而mmap則為程序分配一塊虛擬位址空間。
當程序向glibc申請記憶體時,如果申請記憶體的數量大於乙個閥值的時候,glibc會採用mmap為程序分配一塊虛擬位址空間,而不是採用brk來擴充套件堆頂的指標。預設情況下,此閥值是128k,可以通過函式來修改此值。
#includeint mallopt(int param, int value)
param的取值分別為m_mmap_threshold、m_mmap_max。
value的取值是以位元組為單位的。
m_mmap_threshold是glibc中申請大塊記憶體閥值,大於該閥值的記憶體申請,記憶體管理器將使用mmap系統呼叫申請記憶體,如果小於該閥值的記憶體申請,記憶體管理器使用brk系統呼叫擴充套件堆頂指標。
m_mmap_max是該程序中最多使用mmap分配位址段的數量。
如果在實際的除錯過程中,懷疑某處發生了記憶體洩露,可以檢視該程序的maps表,看程序的堆段或者mmap段的虛擬位址空間是否持續增加,如果是,說明很可能發生了記憶體洩露,如果mmap段虛擬位址空間持續增加,還可以看到各個段的虛擬位址空間的大小,從而可以確定是申請了多大的記憶體,對除錯記憶體洩露類問題可以起到很好的定位作用。
linux下記憶體的統計和記憶體洩露類問題的定位
在產品的開發中,通過對當前系統消耗記憶體總量的統計,可以對產品所需記憶體總量進行精確的評估,從而選擇合適的記憶體晶元與大小,降低產品的成本。在遇到記憶體洩露類問題時,經常會對此束手無策,本文通過對proc下程序相關的檔案進行分析,精確評估系統消耗記憶體的大小,還可以對記憶體洩露類問題的解決提供一種定...
linux下記憶體的統計和記憶體洩露類問題的定位
linux下記憶體的統計和記憶體洩露類問題的定位 wushuan10141 2013 04 08 15 30 20 在產品的開發中,通過對當前系統消耗記憶體總量的統計,可以對產品所需記憶體總量進行精確的評估,從而選擇合適的記憶體晶元與大小,降低產品的成本。在遇到記憶體洩露類問題時,經常會對此束手無策...
linux下記憶體的統計和記憶體洩露類問題的定位
在產品的開發中,通過對當前系統消耗記憶體總量的統計,可以對產品所需記憶體總量進行精確的評估,從而選擇合適的記憶體晶元與大小,降低產品的成本。在遇到記憶體洩露類問題時,經常會對此束手無策,本文通過對proc下程序相關的檔案進行分析,精確評估系統消耗記憶體的大小,還可以對記憶體洩露類問題的解決提供一種定...