執行緒建立未回收導致的記憶體洩漏問題(程序中的堆疊記憶體,並不是malloc出來的記憶體)
預設情況下 pthread_create 建立的執行緒是 joinable的
也就是即便pthread執行緒退出以後,退出狀態也不會釋放,這時候,如果一直建立的話,就會出現問題。
我遇到的就是 pthread_create 返回的 thread id 跟上一次呼叫時候返回的一樣,而pthread_create 也不會報錯。程式也就無法繼續建立執行緒了。。。
解決的辦法就是建立 detach的執行緒,有兩種方法,一種是呼叫 pthread_detach,另一種是指定pthread_create的建立屬性。。。
昨天解決了一個隱蔽的記憶體洩漏問題,原因是pthread_create後的僵死執行緒沒有釋放導致的記憶體持續增長。
現象是這樣的:短時間內程式執行正常,但跑了12小時左右,用top檢視其記憶體佔用居然高達2G,於是馬上意識到有記憶體洩漏。
最 先想到的是malloc/free、new/delete沒有配對,申請的記憶體沒有釋放。於是寫了個跟蹤malloc/free呼叫的模組,不過檢查中並 沒有找到未釋放的記憶體。之後懷疑是不是 free then malloc 導致的記憶體管理錯誤(事實證明雖然free後不是立即回收記憶體,但是接連呼叫free & malloc並不會影響作業系統的記憶體管理),不過寫了個小程式發現並不是這麼回事。
陷入窘境了,只好用最小系統法把功能部分和記憶體分配都給遮蔽掉,這時發現記憶體洩漏依然存在!仔細看top的輸出,幾乎是每次建立執行緒時記憶體就往上漲一點,只是增長速度不是很快,看來是執行緒的問題了。仔細分析發現,之前圖簡單pthread_create (&thread, NULL, &thread_function, NULL);
Linux man page裡有已經說明了這個問題:
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 avoidmemory leaks
也就說執行緒執行完後如果不join的話,執行緒的資源會一直得不到釋放而導致記憶體洩漏!一時的圖快後患無窮啊。
解決辦法:
程式碼 1 // 最簡單的辦法,線上程執行結束後呼叫pthread_detach讓他自己釋放2 pthread_detach(pthread_self());3 4 5 // 或者建立執行緒前設定 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行的那種方法最簡單,線上程函式尾部加上這句話就可以將執行緒所佔用的資源給釋放掉;或者像 5-11 所示的方法設定detach屬性,這樣也會線上程return/pthread_exit後釋放記憶體。
其實仔細想想,valgrind檢查時已經提示了pthread_create沒有釋放的問題,只是之前沒引起注意。其實這樣的問題也只有在長時間執行時,慢慢積累這一點點的記憶體才會暴露出來,看來valgrind的提示也不能置之不理啊。