您好,登錄后才能下訂單哦!
這篇文章主要介紹Linux下如何解決內(nèi)存統(tǒng)計(jì)和內(nèi)存泄露類問題,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
Linux在內(nèi)存使用上的原則是:如果內(nèi)存充足,不用白不用,盡量使用內(nèi)存來緩存一些文件,從而加快進(jìn)程的運(yùn)行速度,而當(dāng)內(nèi)存不足時(shí),會(huì)通過相應(yīng)的內(nèi)存回收策略收回cache內(nèi)存,供進(jìn)程使用。
一、系統(tǒng)總內(nèi)存的分析
可以從proc目錄下的meminfo文件了解到當(dāng)前系統(tǒng)內(nèi)存的使用情況匯總,其中可用的物理內(nèi)存=memfree+buffers+cached,當(dāng)memfree不夠時(shí),內(nèi)核會(huì)通過回寫機(jī)制(pdflush線程)把cached和buffered內(nèi)存回寫到后備存儲(chǔ)器,從而釋放相關(guān)內(nèi)存供進(jìn)程使用,或者通過手動(dòng)方式顯式釋放cache內(nèi)存:
echo 3 > /proc/sys/vm/drop_caches
下圖是海思平臺(tái)下當(dāng)前系統(tǒng)內(nèi)存的總體使用情況,其中可以看到,系統(tǒng)消耗掉了29M的內(nèi)存,下面繼續(xù)分析這些內(nèi)存都是被誰消耗掉了。
# 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 Mapped: 2472 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 |
二、進(jìn)程使用內(nèi)存的統(tǒng)計(jì)
在32位操作系統(tǒng)中,每個(gè)進(jìn)程擁有4G的虛擬內(nèi)存空間,其中0~3GB是每個(gè)進(jìn)程的私有用戶空間,這個(gè)空間對(duì)系統(tǒng)中其他進(jìn)程是不可見的。3~4GB是linux內(nèi)核空間,由系統(tǒng)所有的進(jìn)程以及內(nèi)核所共享的。通過訪問/proc/{pid}/下相關(guān)文件,可以了解每個(gè)線程虛擬內(nèi)存空間的使用情況,從而了解每個(gè)線程所消耗內(nèi)存的多少。
由于我們的產(chǎn)品都是使用多線程方式實(shí)現(xiàn)的,多個(gè)線程共享一個(gè)進(jìn)程的用戶態(tài)虛擬地址空間,虛擬地址空間包含若干區(qū)域,主要有如下幾個(gè)區(qū)域:
1、當(dāng)前執(zhí)行文件的代碼段,該代碼段稱為text段。
2、執(zhí)行文件的數(shù)據(jù)段,主要存儲(chǔ)執(zhí)行文件用到的全局變量,靜態(tài)變量。
3、存儲(chǔ)全局變量和動(dòng)態(tài)產(chǎn)生的數(shù)據(jù)的堆。
4、用于保存局部變量和實(shí)現(xiàn)函數(shù)調(diào)用的棧。
5、采用mmap方式映射到虛擬地址空間中的內(nèi)存段
所以只需要查看任意一個(gè)線程的用戶態(tài)虛擬地址空間分配即可知道屬于同一進(jìn)程的所有線程占用總內(nèi)存的大小??梢酝ㄟ^查看/proc/{pid}/maps文件來獲取相關(guān)的虛擬地址空間內(nèi)容,下文摘列部分典型的內(nèi)容:
# 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可知其權(quán)限為只讀、可執(zhí)行,該段內(nèi)存地址對(duì)應(yīng)于執(zhí)行文件的代碼段,程序的代碼段需加載到內(nèi)存中才可以執(zhí)行。由于其只讀,不會(huì)被修改,所以在整個(gè)系統(tǒng)內(nèi)共享。
第二行:從rw-p可知其權(quán)限為可讀寫,不可執(zhí)行,該段內(nèi)存地址對(duì)應(yīng)于執(zhí)行文件的數(shù)據(jù)段,存放執(zhí)行文件所用到的全局變量、靜態(tài)變量。
第三行:從rwxp可知其權(quán)限是可讀寫,可執(zhí)行,地址空間向上增長,而且不對(duì)應(yīng)文件,是堆段,進(jìn)程使用malloc申請(qǐng)的內(nèi)存放在堆段。每個(gè)進(jìn)程只有一個(gè)堆段,不論是主進(jìn)程,還是不同的線程申請(qǐng)的內(nèi)存,都反映到到進(jìn)程的堆段。堆段向上增長,***可以增長到1GB的位置,即0x40000000,如果大于1GB,glibc將采用mmap的方式,為堆申請(qǐng)一塊內(nèi)存。
第四行:是程序連接的共享庫的內(nèi)存地址。
第五行:是以mmap方式映射的虛擬地址空間。
第六、七行:是線程的棧區(qū)地址段,每個(gè)線程的棧大小都是16K。
第八行:是進(jìn)程的棧區(qū)。關(guān)于棧段,每個(gè)線程都有一個(gè),如果進(jìn)程中有多個(gè)線程,則包含多個(gè)棧段。
三、當(dāng)前系統(tǒng)總內(nèi)存的統(tǒng)計(jì)
1、進(jìn)程占用的總內(nèi)存可以通過上述maps表計(jì)算出來。
2、當(dāng)系統(tǒng)運(yùn)行起來以后,會(huì)把應(yīng)用層相關(guān)的文件掛載到tmpfs文件系統(tǒng)下,海思系統(tǒng)下這部分大概有13M左右,這部分內(nèi)存是以cache方式統(tǒng)計(jì)出來的,但是這部分內(nèi)存cache無法通過回收策略或者顯式的調(diào)用釋放掉。
3、根文件系統(tǒng)ramdisk占用的內(nèi)存。
4、當(dāng)前系統(tǒng)保留內(nèi)存的大小,可以通過查看/proc/sys/vm/min_free_kbytes來獲取或者修改此內(nèi)存的大小。
5、當(dāng)然,當(dāng)系統(tǒng)運(yùn)行起來后,還應(yīng)該留有一定的內(nèi)存用于在硬盤讀寫時(shí)做cache或者網(wǎng)絡(luò)負(fù)荷比較高時(shí)分配skb等,一般需要30M以上。
四、對(duì)調(diào)試內(nèi)存泄露類問題的一些啟示
當(dāng)進(jìn)程申請(qǐng)內(nèi)存時(shí),實(shí)際上是glibc中內(nèi)置的內(nèi)存管理器接收了該請(qǐng)求,隨著進(jìn)程申請(qǐng)內(nèi)存的增加,內(nèi)存管理器會(huì)通過系統(tǒng)調(diào)用陷入內(nèi)核,從而為進(jìn)程分配更多的內(nèi)存。
針對(duì)堆段的管理,內(nèi)核提供了兩個(gè)系統(tǒng)調(diào)用brk和mmap,brk用于更改堆頂?shù)刂?,而mmap則為進(jìn)程分配一塊虛擬地址空間。
當(dāng)進(jìn)程向glibc申請(qǐng)內(nèi)存時(shí),如果申請(qǐng)內(nèi)存的數(shù)量大于一個(gè)閥值的時(shí)候,glibc會(huì)采用mmap為進(jìn)程分配一塊虛擬地址空間,而不是采用brk來擴(kuò)展堆頂?shù)闹羔?。缺省情況下,此閥值是128K,可以通過函數(shù)來修改此值。
#include <malloc.h>
Int mallopt(int param, int value)
Param的取值分別為M_MMAP_THRESHOLD、M_MMAP_MAX。
Value的取值是以字節(jié)為單位的。
M_MMAP_THRESHOLD是glibc中申請(qǐng)大塊內(nèi)存閥值,大于該閥值的內(nèi)存申請(qǐng),內(nèi)存管理器將使用mmap系統(tǒng)調(diào)用申請(qǐng)內(nèi)存,如果小于該閥值的內(nèi)存申請(qǐng),內(nèi)存管理器使用brk系統(tǒng)調(diào)用擴(kuò)展堆頂指針。
M_MMAP_MAX是該進(jìn)程中最多使用mmap分配地址段的數(shù)量。
如果在實(shí)際的調(diào)試過程中,懷疑某處發(fā)生了內(nèi)存泄露,可以查看該進(jìn)程的maps表,看進(jìn)程的堆段或者mmap段的虛擬地址空間是否持續(xù)增加,如果是,說明很可能發(fā)生了內(nèi)存泄露,如果mmap段虛擬地址空間持續(xù)增加,還可以看到各個(gè)段的虛擬地址空間的大小,從而可以確定是申請(qǐng)了多大的內(nèi)存,對(duì)調(diào)試內(nèi)存泄露類問題可以起到很好的定位作用。
以上是“Linux下如何解決內(nèi)存統(tǒng)計(jì)和內(nèi)存泄露類問題”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。