昨天解決了一個隱蔽的內(nèi)存泄漏問題,原因是pthread_create后的僵死線程沒有釋放導致的內(nèi)存持續(xù)增長。
現(xiàn)象是這樣的:短時間內(nèi)程序運行正常,但跑了12小時左右,用top查看其內(nèi)存占用居然高達2G,于是馬上意識到有內(nèi)存泄漏。
最先想到的是malloc/free、new/delete沒有配對,申請的內(nèi)存沒有釋放。于是寫了個跟蹤malloc/free調(diào)用的模塊,不過檢查中并沒有找到未釋放的內(nèi)存。之后懷疑是不是 free then malloc 導致的內(nèi)存管理錯誤(事實證明雖然free后不是立即回收內(nèi)存,但是接連調(diào)用free & malloc并不會影響操作系統(tǒng)的內(nèi)存管理),不過寫了個小程序發(fā)現(xiàn)并不是這么回事。
陷入窘境了,只好用最小系統(tǒng)法把功能部分和內(nèi)存分配都給屏蔽掉,這時發(fā)現(xiàn)內(nèi)存泄漏依然存在!仔細看top的輸出,幾乎是每次創(chuàng)建線程時內(nèi)存就往上漲一點,只是增長速度不是很快,看來是線程的問題了。仔細分析發(fā)現(xiàn),之前圖簡單 pthread_create (&thread, NULL, &thread_function, NULL); 就這么寫了,參數(shù)2沒有設置線程結束后自動detach,并且沒有使用pthread_join或pthread_detach釋放執(zhí)行結束后線程的空間!
Linux man page 里有已經(jīng)說明了這個問題:
When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore, pthread_join must be called once for each joinable thread created to avoid memory leaks.
也就說線程執(zhí)行完后如果不join的話,線程的資源會一直得不到釋放而導致內(nèi)存泄漏!一時的圖快后患無窮啊。
解決辦法:
代碼 1 // 最簡單的辦法,在線程執(zhí)行結束后調(diào)用pthread_detach讓他自己釋放
2 pthread_detach(pthread_self());
3
4
5 // 或者創(chuàng)建線程前設置 PTHREAD_CREATE_DETACHED 屬性
6 pthread_attr_t attr;
7 pthread_t thread;
8 pthread_attr_init (&attr);
9 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
10 pthread_create (&thread, &attr, &thread_function, NULL);
11 pthread_attr_destroy (&attr);
第2行的那種方法最簡單,在線程函數(shù)尾部加上這句話就可以將線程所占用的資源給釋放掉;或者像 5-11 所示的方法設置detach屬性,這樣也會在線程return/pthread_exit后釋放內(nèi)存。
其實仔細想想,valgrind檢查時已經(jīng)提示了pthread_create沒有釋放的問題,只是之前沒引起注意。其實這樣的問題也只有在長時間運行時,慢慢積累這一點點的內(nèi)存才會暴露出來,看來valgrind的提示也不能置之不理啊。
from:
http://www.cnblogs.com/bits/archive/2009/12/04/no_join_or_detach_memory_leak.html
posted on 2010-01-14 16:40
chatler 閱讀(3105)
評論(2) 編輯 收藏 引用 所屬分類:
Linux_Coding