Linux進程內存分析和內存泄漏定位


在Linux產品開發過程中,通常需要注意系統內存使用量,和評估單一進程的內存使用情況,便於我們選取合適的機器配置,來部署我們的產品。

Linux本身提供了一些工具方便我們達成這些需求,查看進程實時資源top工具,更詳細的進程內存堆棧情況,pmap工具,Linux進程運行時狀態信息也會保存在proc目錄下,相應進程ID目錄下,這里有很豐富的信息,先討論進程內存。

       借助網上大部分人的說法,Linux系統在內存分配上:內存充足時,盡量使用內存來緩存一些文件,從而加快進程的運行速度,而當內存不足時,會通過相應的內存回收策略收回cache內存,供進程使用。

 

雖然在Linux平台下做開發,但是對Linux內存管理並不熟悉,不過上述說法,可以通過下面的方法來驗證:

一、系統內存。

在proc目錄下的meminfo文件描述系統內存的使用情況,可用的物理內存=memfree+buffers+cached,下圖是suse10 的情況:

MemTotal 是全部物理內存,我的虛擬器配置的是1G內存,memfree+buffers+cached = 438752,大概還有430M可用,因為我的機器上只跑着apache和redis進程。

當memfree不夠時,內核會通過回寫機制(pdflush線程)把cached和buffered內存回寫到后備存儲器,也可以通過手動方式顯式釋放cache內存

       echo 3 > /proc/sys/vm/drop_caches

釋放后,Buffers和Cached 表小了好多,MemFree變大了許多,memfree+buffers+cached三者和大約仍然是430M。

 

二、進程內存

在32位操作系統中,每個進程擁有4G的虛擬內存空間,其中0~3GB是每個進程的私有用戶空間,這個空間對系統中其他進程是不可見的。3~4GB是linux內核空間,由系統所有的進程以及內核所共享的。通過訪問/proc/{pid}/下相關文件,可以查看進程內存情況。

如果進程內含有多個線程,多個線程共享一個進程的用戶態虛擬地址空間,虛擬地址空間包含若干區域,主要有如下幾個區域:

1、當前執行文件的代碼段,該代碼段稱為text段。

2、執行文件的數據段,主要存儲執行文件用到的全局變量,靜態變量。(全局和static)

3、存儲全局變量和動態產生的數據的堆。(堆)

4、用於保存局部變量和實現函數調用的棧。(棧)

5、采用mmap方式映射到虛擬地址空間中的內存段

這是我的機器上,redis 進程的情況,

第一行:從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,可以通過函數來修改此值。

             #include<malloc.h>

             Intmallopt(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段虛擬地址空間持續增加,還可以看到各個段的虛擬地址空間的大小,從而可以確定是申請了多大的內存,對調試內存泄露類問題可以起到很好的定位作用。

轉自:http://blog.csdn.net/babykakaluo/article/details/9763605


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM