linux 内存泄漏 定位,一种内存泄露检查和定位的方法
一個系統(tǒng)后臺服務(wù)進(jìn)程,可能包括多個線程,在生成環(huán)境下要求系統(tǒng)程序能夠穩(wěn)定長時間穩(wěn)定運(yùn)行而不宕機(jī)。其中一個基本的前提就是需要保證系統(tǒng)程序不存在內(nèi)存泄露。那么,該如何判讀系統(tǒng)程序是否存在內(nèi)存泄露呢?如果存在,又該如何檢測呢?
0.判讀系統(tǒng)程序是否存在內(nèi)存泄露
對于頻繁快速申請內(nèi)存的應(yīng)用,可以允許下面的命令:
top
-p `pidof YourProgrogram`
如果看到系統(tǒng)內(nèi)存使用率一直上身,沒有下降,就說明很可能存在內(nèi)存泄露。
對于申請、使用內(nèi)存比較緩慢的應(yīng)用程序,可以通過下面的命令,觀測一天乃至一周內(nèi)內(nèi)存使用率的變化:
for
((i=0;i<100000;i++)); do pidstat -p `pidof YourProgram` -tr | tee
-a thread_mem_static.txt; sleep 10; done
如果上面顯示的RSS的內(nèi)存隨著時間推移不斷增加,且不符合程序預(yù)期,那么很可能存在內(nèi)存泄露。
1.定位內(nèi)存泄露的線程或代碼位置
檢查主進(jìn)程的每個線程的page
fault的頻率,雖然page
fault頻率高的不一定有內(nèi)存泄露,但有內(nèi)存泄露的線程的page
fault的頻率一定很高。而體現(xiàn)每個線程Page
fault頻率的指標(biāo)就是上圖中每個線程的minflt/s值,如果它的值一直偏高,就說明該線程反復(fù)申請內(nèi)存或者不停在棧上使用buffer,此時就需要利用gdb打印出每個線程信息,可以參考下面的gdb命令:
gdb
-q --batch --ex "thread apply all bt" -p `pidof tmem`
根據(jù)上面對應(yīng)的線程號找到相應(yīng)函數(shù),然后進(jìn)行跟蹤,可以參考下面的示例:
上圖中顯示線程14178
(mem_funcs)線程頻繁使用新的內(nèi)存,查看代碼,果然存在內(nèi)存泄露:
需要強(qiáng)調(diào)的是,只有RSS不一直增加,哪怕minflt/s一直增加,也表明沒有內(nèi)存泄露,比如下面的測試程序,頻繁使用棧上空間:
void
internal_mem_funcs(void)
{
long
int test[MAX_BUF_LEN] = {0,};
//long
int * test = (long int *)malloc(MAX_BUF_LEN * sizeof(long int));
int
i = 0;
for
(i = 0; i < MAX_BUF_LEN; i++) {
test[i]
= random();
}
return;
}
它的pidstat統(tǒng)計圖如下:
2.常見的內(nèi)存泄露方式
筆者最近分析了一個系統(tǒng)服務(wù)進(jìn)程內(nèi)存泄露的問題,下面總結(jié)了一些代碼中很容易出現(xiàn)內(nèi)存泄露的地方:函數(shù)正常成功執(zhí)行的時候有釋放內(nèi)存,但在執(zhí)行異常退出的時候,沒有釋放所有先前申請的內(nèi)存;
對類似strdup()/strndup()/g_strdup()的函數(shù)的返回值,使用完之后,沒有釋放內(nèi)存的意識;
不同模塊或者層次的代碼相互調(diào)用的時候,沒有統(tǒng)一約定好是調(diào)用者申請內(nèi)存、釋放內(nèi)存還是被調(diào)用者申請、釋放內(nèi)存,抑或是調(diào)用者申請/釋放內(nèi)存,被調(diào)用者釋放/申請內(nèi)存,導(dǎo)致后面遺忘釋放內(nèi)存或者重復(fù)釋放內(nèi)存;
Java/c++中對異常處理的流程中,遺忘沒有釋放內(nèi)存;
使用了一些不太熟悉的第三方庫代碼,對類似句柄、描述符、對象相關(guān)的API了解不夠深入,導(dǎo)致沒有也不知道該如何釋放內(nèi)存。
總結(jié)
以上是生活随笔為你收集整理的linux 内存泄漏 定位,一种内存泄露检查和定位的方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NFC基础知识学习
- 下一篇: intel i218v千兆网卡 linu