內存泄漏的檢測、定位和解決經驗總結
發表于:2008-02-13來源:作者:點擊數:
標簽:內存泄漏
MI LY: 宋體">【摘要】 結合 局端MCU 項目中 CSS 、 NMS 模塊內存泄漏檢測、修正的過程,簡要介紹了內存泄漏檢測的工具,提出了內存泄漏檢測的一些方法 ( 怎樣對程序結構進行改造,怎樣對程序進行隔離以易于進行內存泄漏檢測 ) ??偨Y了內存泄漏檢測過程中成
MILY: 宋體">【摘要】
結合局端MCU項目中CSS、NMS模塊內存泄漏檢測、修正的過程,簡要介紹了內存泄漏檢測的工具,提出了內存泄漏檢測的一些方法(怎樣對程序結構進行改造,怎樣對程序進行隔離以易于進行內存泄漏檢測)??偨Y了內存泄漏檢測過程中成功和失敗的體會,希望能對后來者有所啟發。
【關鍵詞】
內存泄漏
一、故障或失誤概況
局端MCU項目中CSS(Conference Schedule System)、NMS(NetWork Management System)模塊自2.03版本起就有內存泄露的問題,開發 NGN版本時也花過大量的精力來爭取解決這個問題,雖然也修正了一些內存泄漏,但最終檢測工具表面現象顯示剩下的內存泄露都是所使用的開發庫的代碼產生的,于是也就大意的認為是所使用的ACE/TAO庫本身有內存泄漏,于是無果而終,使這兩個模塊的內存泄漏問題一直延續到2.03.20x版本。
由于后續測試部和開發部進行測試時引入了Robot來進行自動測試,使業務操作量巨升,此時CSS模塊的內存泄漏問題就更明顯了,從程序啟動時的13M內存,經過一兩個月后可以飆升到200 M左右,正因為此局端MCU項目好幾個程序都采用了看門狗的方式來定時檢測程序的狀態防止程序當掉。
由于問題比較嚴重,于是再次進行內存泄漏問題的攻關,測試時NMS模塊業務操作量小內存泄漏不明顯,于是此次攻關重點是查CSS的內存泄漏問題。
此次再次進行CSS行內存泄露問題的研究,力爭解決CSS的內存泄露問題,實在找不到解決方案(例如為所使用的開發庫的原因)也定位出具體原因供項目組參考。
二、診斷過程
2.1工具介紹
目前Windows平臺上流行的內存泄露檢測工具有Rational Purify、BoundsChecker、insure++,由于CSS較復雜又是多線程采用Rational Purify工具程序就啟動不起來,無法進行檢測;parasoft 公司的insure++工具傳說中比較好用,但由于我們公司沒有相應的licence無法使用;最后選擇采用限制版的BoundsChecker來進行檢測。
還有就是要一個好的實時檢測程序使用內存狀況并能實時記錄下每個時刻內存使用情況的工具,我們這里使用的是本部傳輸產品測試部自己開發的一個小工具MemSample。(見附錄1)
對于工具方面這也是個問題,若每個公司都有個統一可用工具列表,然后附上相應的使用說明就可以省了許多精力和時間?,F在好多工具都是自己去浩如煙海的網上找,有些還需要licence等,這是個很大的精力浪費。
2.2診斷概況
CSS模塊為后臺服務程序通過訪問Web頁面的形式來對外提供服務,運行了該模塊的程序過一段時間后機器性能明顯下降,經檢測為內存嚴重消耗。測試部使用內存監視工具MemSample對各模塊的內存進行監測,發現在一個月內CSS程序占用的內存從初始的13M飆升到200多M。
由現象可以判斷肯定是存在內存泄漏問題,由于CSS對外提供服務接口繁多一時不知道那個接口導致的內存泄漏,因此確定如下測試過程:
l 采用CPPUNIT測試框架輔助以樁程序的方式來模擬Web頁面手工操作的方式來調用相應接口進行測試。
l 程序測試過程中采用內存泄漏代碼級檢測工具BoundsChecker全程跟蹤程序中內存分配和釋放情況。
l 采用內存監測工具MemSample對程序占用的整體內存進行監測并采集各時間段內存占用數據。
經過第一種測試方法發現了程序中存在的一些內存泄漏,并解決之,但解決之后發現還是存在內存泄漏,通過分析發現模擬測試步驟和真實環境下的操作唯一的不同點就是:
模擬測試是在程序內部直接調用接口,而真實環境下是通過訪問Web頁面,Web頁面再通過CORBA協議來調用程序接口。即模擬測試少了CORBA調用那部分的操作,為此重新制定第二種測試方法:
測試方法2:真實操作環境下進行測試
l 由于接口繁多,重點挑一兩個使用頻繁的接口進行測試。
l 人工訪問調用所測接口的那個Web頁面,不斷頻繁刷新,保證和真實操作環境完全一致。
l 測試過程中啟動內存監測工具MemSample對CSS占用內存進行監測并采集各時間段內存占用數據。
測試后發現所測接口均存在內存泄漏,每次接口調用都會有幾十K的內存泄漏,此時擴展到其它接口發現所有使用CORBA協議通過Web頁面調用的接口均存在內存泄漏。比較兩種測試方法可以初步確定是在調用CORBA協議部分的代碼出現了內存泄漏,下面進行整個檢測過程詳細描述。
2.3診斷過程
采用BoundsChecker檢測和Rational Purify工具不一樣,Rational Purify可以在程序運行中隨時給出即時的內存泄漏報告,而使用BoundsChecker則只有在程序自行結束后才會觸發它去收集數據給出內存泄漏報告(注意:必須是程序自己運行完畢退出,而不能人為的去關閉該程序否則得不到內存泄漏報告)。
2.3.1對程序的改造
由于要讓程序自動結束,所以要對程序結構進行改造,前段時間部門推行的單元測試為此次內存泄漏檢測提供了很好的基礎。
CSS模塊為單元測試專門創建了一個新的VC Project,共用CSS中的所有代碼,但自己工程中的單元測試代碼又不會影響CSS原來的代碼。此次進行內存泄漏的檢測就首先打算運行單元測試的代碼然后檢測是否有內存泄漏。
單元測試程序改造如下:
1)程序啟動時開啟兩個線程,一個CSS線程負責正常啟動CSS,另一個測試線程負責運行測試用例對已經正常啟動的CSS進行測試。
2)測試線程運行測試用例完畢后要讓CSS線程退出,并結束自己,只有這樣BoundsChecker才能拿到內存泄漏數據。
2.3.2內存泄漏檢測
第一次內存泄漏檢測,CSS測試程序運行一遍測試用例正常退出后,得到BoundsChecker的檢測報告顯示:
l 所有采取單態模式的類中的相應的指針指向的動態分配的對象都沒有被釋放。
l 線程被異常終止時,該線程中動態分配的內存沒有釋放掉。
l 動態分配的全局變量(對象)沒有被釋放掉。
l 絕大部分的內存泄漏集中在ACE/TAO(ACE的CORBA庫)提供的一些函數里。
其中前三種情況就是1.問題描述中提到的在第一次內存泄漏檢測就解決的,最后一個是造成內存泄漏問題嚴重的罪魁禍首,在第二次內存泄漏檢測才徹底解決,這里列下相應的解決方法和思路。
2.3.3內存泄漏修正方法
BoundsChecker Data Collection設置中將跟蹤的call stack深度加大即可以晰的看到每個內存泄漏是從哪個函數哪條語句產生的。BoundsChecker出的報告中內存泄漏數據和資源泄漏數據對于查找內存泄漏問題都是非常有幫助的。[見附錄2、3]
根據報告進行內存泄漏定位發現泄漏分為兩種:
1)在程序關閉時候的內存泄漏,只有程序關閉時才發生的內存泄漏,如一些動態分配的全局對象,線程沒有正常退出而是直接被Terminate掉等。
2)程序運行中的內存泄漏,即運行中會不斷發生泄漏,如一段代碼動態分配了內存忘釋放了,這樣這段代碼每次運行都會產生內存泄漏。
2.3.3.1程序關閉時內存泄漏檢測和修正方法
雖然程序關閉時才發生的內存泄漏不會導致程序運行中內存使用的增長,但由于BoundsChecker給出的報告中只給出程序運行期間發生的所有內存泄漏,所有關閉時內存泄漏和運行時內存泄漏都混雜在一起不好定位,為此首先要解決關閉時的內存泄漏問題,由于關閉時內存泄漏一般都是動態分配的全局變量沒釋放、線程不是正常退出等情況產生的所以比較好定位。解決方法如下:
1)所有動態分配的全局變量在程序退出時都Delete掉。
2)讓所有線程都正常運行結束退出,而不是被異常Terminate掉。
3)所有使用單態模式的類都必須有專門的內存清理函數在程序結束前調用。