本發(fā)明涉及內(nèi)存檢測領(lǐng)域,特別是涉及一種內(nèi)存泄漏檢測方法和裝置。
背景技術(shù):
內(nèi)存泄漏是指堆內(nèi)存的泄漏。堆內(nèi)存是指程序從堆中分配的,大小任意的,使用完后必須顯示釋放的內(nèi)存。應(yīng)用程序一般使用malloc、realloc、new等函數(shù)從堆中分配到一塊內(nèi)存,使用完后,程序必須負責相應(yīng)的調(diào)用free或delete釋放該內(nèi)存塊,否則,這塊內(nèi)存就不能被再次使用,也就是這塊內(nèi)存泄漏了。
在常規(guī)的客戶端性能專項測試中,內(nèi)存使用情況是重點關(guān)注的一個指標。Windows調(diào)試工具集(the Debugging Tools for Windows)中的UMDH工具能監(jiān)控到內(nèi)存泄漏的問題點,得到內(nèi)存泄漏處的堆棧。UMDH監(jiān)控Windows系統(tǒng)函數(shù)中的內(nèi)存分配函數(shù),通過統(tǒng)計比較使用者手動指定的開始和結(jié)束兩個時間點內(nèi)存分配情況得到這兩個時間點之間的內(nèi)存泄漏,然而手動指定難以精確,且得到的數(shù)據(jù)不全面。
技術(shù)實現(xiàn)要素:
基于此,有必要針對傳統(tǒng)的內(nèi)存泄漏檢測手動指定時間點不夠精確且得到的數(shù)據(jù)不全面的問題,提供一種內(nèi)存泄漏檢測方法,監(jiān)控的時間點精確且監(jiān)控的數(shù)據(jù)全面。
此外,還有必要提供一種內(nèi)存泄漏檢測裝置,監(jiān)控的時間點精確且監(jiān)控的數(shù)據(jù)全面。
一種內(nèi)存泄漏檢測方法,包括以下步驟:
在被測進程啟動時加載預(yù)設(shè)的內(nèi)存監(jiān)控動態(tài)鏈接庫;
通過所述內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口;
通過掛鉤函數(shù)調(diào)用所述內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接 口,收集被測進程啟動時的內(nèi)存分配信息,以及收集被測進程退出時的內(nèi)存分配信息;
對所述被測進程啟動時的內(nèi)存分配信息及退出時的內(nèi)存分配信息進行比較得出內(nèi)存泄漏信息。
一種內(nèi)存泄漏檢測裝置,包括:
加載模塊,用于在被測進程啟動時加載預(yù)設(shè)的內(nèi)存監(jiān)控動態(tài)鏈接庫;
掛鉤模塊,用于通過所述內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口;
收集模塊,用于通過掛鉤函數(shù)調(diào)用所述內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口,收集被測進程啟動時的內(nèi)存分配信息,以及收集被測進程退出時的內(nèi)存分配信息;
比較模塊,用于對所述被測進程啟動時的內(nèi)存分配信息及退出時的內(nèi)存分配信息進行比較得出內(nèi)存泄漏信息。
上述內(nèi)存泄漏檢測方法和裝置,通過在被測進程啟動時加載內(nèi)存監(jiān)控動態(tài)鏈接庫,通過內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù),收集被測進程啟動時的內(nèi)存分配信息和退出后的內(nèi)存分配信息,通過比較被測進程啟動時和退出時內(nèi)存分配信息,得出內(nèi)存泄漏信息,監(jiān)控了被測進程從啟動開始到退出的整個過程中的內(nèi)存分配信息,監(jiān)控的時間點精確,得到的數(shù)據(jù)全面,且統(tǒng)計出來的結(jié)果是始終沒有釋放的,則得出的內(nèi)存泄漏信息更加準確。
附圖說明
圖1A為一個實施例中終端的內(nèi)部結(jié)構(gòu)示意圖;
圖1B為一個實施例中服務(wù)器的內(nèi)部結(jié)構(gòu)示意圖;
圖2為一個實施例中內(nèi)存泄漏檢測方法的流程圖;
圖3為函數(shù)調(diào)用關(guān)系示意圖;
圖4為一個實施例中將內(nèi)存監(jiān)控信息發(fā)送給數(shù)據(jù)處理進程,由該數(shù)據(jù)處理進程對該內(nèi)存監(jiān)控信息進行處理的具體流程圖;
圖5A為被測進程與數(shù)據(jù)處理進程傳輸數(shù)據(jù)的示意圖;
圖5B為進程間傳輸數(shù)據(jù)的過程示意圖;
圖6為數(shù)據(jù)緩存示意圖;
圖7為高速緩存機制示意圖;
圖8為內(nèi)存快照中內(nèi)存地址比較示意圖;
圖9為內(nèi)存快照中采用函數(shù)堆棧比較的示意圖;
圖10為一個堆棧的變化曲線圖;
圖11為一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖;
圖12為另一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖;
圖13為另一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖;
圖14為另一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖。
具體實施方式
為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點更加清楚明白,以下結(jié)合附圖及實施例,對本發(fā)明進行進一步詳細說明。應(yīng)當理解,此處所描述的具體實施例僅僅用以解釋本發(fā)明,并不用于限定本發(fā)明。
可以理解,本發(fā)明所使用的術(shù)語“第一”、“第二”等可在本文中用于描述各種元件,但這些元件不受這些術(shù)語限制。這些術(shù)語僅用于將第一個元件與另一個元件區(qū)分。舉例來說,在不脫離本發(fā)明的范圍的情況下,可以將第一客戶端稱為第二客戶端,且類似地,可將第二客戶端稱為第一客戶端。第一客戶端和第二客戶端兩者都是客戶端,但其不是同一客戶端。
圖1A為一個實施例中終端的內(nèi)部結(jié)構(gòu)示意圖。如圖1A所示,該終端包括通過系統(tǒng)總線連接的處理器、存儲介質(zhì)、內(nèi)存、網(wǎng)絡(luò)接口、聲音采集裝置、顯示屏、揚聲器和輸入裝置。其中,終端的存儲介質(zhì)存儲有操作系統(tǒng),還包括一種內(nèi)存泄漏檢測裝置,該內(nèi)存泄漏檢測裝置用于實現(xiàn)一種內(nèi)存泄漏檢測方法。該處理器用于提供計算和控制能力,支撐整個終端的運行。終端中的內(nèi)存為存儲介質(zhì)中的內(nèi)存泄漏裝置的運行提供環(huán)境,網(wǎng)絡(luò)接口用于與服務(wù)器進行網(wǎng)絡(luò)通信,如發(fā)送游戲數(shù)據(jù)請求至服務(wù)器,接收服務(wù)器返回的游戲數(shù)據(jù)等。終端的顯示屏可以是液晶顯示屏或者電子墨水顯示屏等,輸入裝置可以是顯示屏上覆蓋的觸 摸層,也可以是終端外殼上設(shè)置的按鍵、軌跡球或觸控板,也可以是外接的鍵盤、觸控板或鼠標等。該終端可以是手機、平板電腦或者個人數(shù)字助理。本領(lǐng)域技術(shù)人員可以理解,圖1A中示出的結(jié)構(gòu),僅僅是與本申請方案相關(guān)的部分結(jié)構(gòu)的框圖,并不構(gòu)成對本申請方案所應(yīng)用于其上的終端的限定,具體的終端可以包括比圖中所示更多或更少的部件,或者組合某些部件,或者具有不同的部件布置。
圖1B為一個實施例中服務(wù)器的內(nèi)部結(jié)構(gòu)示意圖。如圖1B所示,該服務(wù)器包括通過系統(tǒng)總線連接的處理器、存儲介質(zhì)、內(nèi)存、網(wǎng)絡(luò)接口、顯示屏和輸入裝置。其中,該服務(wù)器的存儲介質(zhì)存儲有操作系統(tǒng)、數(shù)據(jù)庫和內(nèi)存泄漏檢測裝置,數(shù)據(jù)庫中存儲有游戲場景數(shù)據(jù)、游戲用戶數(shù)據(jù)等,該內(nèi)存泄漏裝置用于實現(xiàn)適用于服務(wù)器的一種內(nèi)存泄漏檢測方法。該服務(wù)器的處理器用于提供計算和控制能力,支撐整個服務(wù)器的運行。該服務(wù)器的內(nèi)存為存儲介質(zhì)中的內(nèi)存泄漏裝置的運行提供環(huán)境。該服務(wù)器的顯示屏可以是液晶顯示屏或者電子墨水顯示屏等,輸入裝置可以是顯示屏上覆蓋的觸摸層,也可以是終端外殼上設(shè)置的按鍵、軌跡球或觸控板,也可以是外接的鍵盤、觸控板或鼠標等。該服務(wù)器的網(wǎng)絡(luò)接口用于據(jù)以與外部的終端通過網(wǎng)絡(luò)連接通信,比如接收終端發(fā)送的游戲數(shù)據(jù)請求以及向終端返回游戲數(shù)據(jù)等。服務(wù)器可以用獨立的服務(wù)器或者是多個服務(wù)器組成的服務(wù)器集群來實現(xiàn)。本領(lǐng)域技術(shù)人員可以理解,圖1B中示出的結(jié)構(gòu),僅僅是與本申請方案相關(guān)的部分結(jié)構(gòu)的框圖,并不構(gòu)成對本申請方案所應(yīng)用于其上的服務(wù)器的限定,具體的服務(wù)器可以包括比圖中所示更多或更少的部件,或者組合某些部件,或者具有不同的部件布置。
內(nèi)存泄漏是指應(yīng)用程序使用malloc、realloc、new等函數(shù)從堆中分配到一塊內(nèi)存,使用完后,未調(diào)用free或delete函數(shù)釋放該內(nèi)存塊導(dǎo)致的。傳統(tǒng)的內(nèi)存泄漏檢測方法比較的是使用者指定的兩個時間點的內(nèi)存泄漏情況,而有些應(yīng)用程序在退出后才釋放分配的內(nèi)存,導(dǎo)致檢測的內(nèi)存泄漏數(shù)據(jù)不全面,也不準確。本發(fā)明中的內(nèi)存泄漏檢測方法,通過在被測進程啟動時加載內(nèi)存監(jiān)控動態(tài)鏈接庫并執(zhí)行其中的函數(shù),在被測進程啟動時開始監(jiān)控內(nèi)存分配信息,在被測進程退出時仍然執(zhí)行加載后的內(nèi)存監(jiān)控動態(tài)鏈接庫監(jiān)控被測進程退出后的內(nèi)存分配 信息,通過比較被測進程啟動時和退出時內(nèi)存分配信息,得出內(nèi)存泄漏信息,監(jiān)控了被測進程從啟動開始到退出的整個過程中的內(nèi)存分配信息,監(jiān)控的時間點精確,得到的數(shù)據(jù)全面,且得出內(nèi)存泄漏信息更加準確。
其中,malloc函數(shù),即memory allocation,動態(tài)內(nèi)存分配函數(shù),若分配成功,則返回指向被分配內(nèi)存的指針,否則返回空指針。
realloc函數(shù),即reset allocation,動態(tài)內(nèi)存調(diào)整函數(shù),若重新分配成功,則返回指向被分配內(nèi)存的指針,否則返回空指針。
new相當于一個函數(shù),在內(nèi)存開辟完空間后,返回這個空間的首地址。
free或delete函數(shù),釋放內(nèi)存。
內(nèi)存分配信息可包括內(nèi)存分配地址、內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配地址和內(nèi)存分配大小。
圖2為一個實施例中內(nèi)存泄漏檢測方法的流程圖。如圖2所示,一種內(nèi)存泄漏檢測方法,包括以下步驟:
步驟202,在被測進程啟動時加載預(yù)設(shè)的內(nèi)存監(jiān)控動態(tài)鏈接庫。
具體地,首先采用靜態(tài)注入的方法,在啟動被測進程前使用detours工具包中的setdll.exe修改進程的可執(zhí)行文件(.exe文件),使被測進程啟動時自動加載預(yù)設(shè)的內(nèi)存監(jiān)控動態(tài)鏈接庫(DLL,Dynamic Link Library),從而hook(掛鉤)內(nèi)存分配函數(shù)和/或windows系統(tǒng)API(Application Programming Interface,應(yīng)用程序編程接口)。
步驟204,通過該內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口。
具體地,在內(nèi)存監(jiān)控動態(tài)鏈接庫中利用微軟提供的detours庫來實現(xiàn)hook(掛鉤)C/C++標準庫中的內(nèi)存分配函數(shù)(malloc、free和realloc等)的功能?;蛘?,hook windows系統(tǒng)應(yīng)用程序編程接口,即hook更底層的HeapAlloc系列函數(shù)(包括HeapAlloc、HeapFree和HeapRealloc)或hook底層的系統(tǒng)函數(shù)(RtAllocateHeap等)。HeapAlloc函數(shù)用來在指定的堆上分配內(nèi)存,并且分配后的內(nèi)存不可移動。采用hook C/C++標準庫中的內(nèi)存分配函數(shù),能大量去掉 windows系統(tǒng)函數(shù)的影響,提高結(jié)果的精確性。
此外,還可同時在hook內(nèi)存分配函數(shù)和windows系統(tǒng)應(yīng)用程序編程接口之間切換。
在對malloc/free兩個函數(shù)進行hook的過程中,可能會出現(xiàn)找不到地址的情況,其原因跟標準庫的鏈接方式有關(guān)系,標準庫函數(shù)既可以從一個libc*.lib靜態(tài)鏈接,也可以從一個msvcrt*.dll動態(tài)鏈接到程序中。當靜態(tài)鏈接到程序時,一個程序得到它自己私有的版本的標準庫函數(shù);當動態(tài)鏈接程序時,一個程序共享DLL中版本的靜態(tài)標準庫函數(shù)。在獲取malloc/free地址時需進行區(qū)分。
圖3為函數(shù)調(diào)用關(guān)系示意圖。如圖3所示,new分配內(nèi)存后,通過調(diào)用malloc函數(shù)、heapalloc函數(shù)收集內(nèi)存分配信息。
步驟206,通過掛鉤函數(shù)調(diào)用該內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口,收集被測進程啟動時的內(nèi)存分配信息,以及收集被測進程退出時的內(nèi)存分配信息。
具體地,內(nèi)存監(jiān)控動態(tài)鏈接庫主要監(jiān)控內(nèi)存中malloc操作、free操作,包括內(nèi)存分配的大小、內(nèi)存分配的地址、內(nèi)存釋放的地址、內(nèi)存分配的函數(shù)堆棧等。hook函數(shù)調(diào)用內(nèi)存分配函數(shù)malloc或free,通過記錄malloc操作和free操作,從而收集被測進程啟動時的內(nèi)存分配信息。該內(nèi)存分配信息可包括內(nèi)存分配地址、內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配地址和內(nèi)存分配大小。
malloc用于收集內(nèi)存分配信息。free函數(shù)用于收集內(nèi)存釋放信息。內(nèi)存釋放信息可包括內(nèi)存釋放地址和/或內(nèi)存釋放的函數(shù)堆棧等。
malloc系列函數(shù)的申明如下:
void*__cdecl malloc(_In_size_t_Size);
void__cdecl free(_Inout_opt_void*_Memory);
void*__cdecl realloc(_In_opt_void*_Memory,_In_size_t_NewSize);
從malloc系列函數(shù)申明中可以看出,地址和大小從函數(shù)調(diào)用的參數(shù)或返回值可以直接獲得,堆棧則需要調(diào)用dbghelp.dll中提供的函數(shù)獲取,具體方法是調(diào)用系統(tǒng)函數(shù)LoadLibrary()加載dbghelp.dll,調(diào)用如下:
HMODULE m_dbgHelp=LoadLibrary(“dbghelp.dll”);
然后通過函數(shù)GetProcAddress()獲取DLL中具體函數(shù)地址。
具體有兩個函數(shù)可以獲取堆棧,CaptureStackBackTrace()和StackWalk64()。兩者有些區(qū)別,CaptureStackBackTrace是windows系統(tǒng)函數(shù),調(diào)用一次可獲取全部堆棧,速度快;StackWalk64調(diào)用一次只能獲取一層堆棧,使用時需要循環(huán)調(diào)用才能獲取全部堆棧,速度慢,能獲取的堆棧較多。
例如,在funcB中調(diào)用CaptureStackBackTrace(),獲得的堆棧為:
funcB()
funcA()
main()
若在funcB中調(diào)用StackWalk64(),只能獲得funcB(),需要再調(diào)用一次獲得funcA(),循環(huán)調(diào)用,直到不能再獲取堆棧。
在個實施例中,上述內(nèi)存泄漏檢測方法還包括:采用堆棧全局獲取函數(shù)(如CaptureStackBackTrace)獲取堆棧,如果獲取失敗,則再采用堆棧局部獲取函數(shù)(如StackWalk64)獲取一次。
步驟208,對該被測進程啟動時的內(nèi)存分配信息及退出時的內(nèi)存分配信息進行比較得出內(nèi)存泄漏信息。
具體地,該內(nèi)存分配信息可包括內(nèi)存分配地址、內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配地址和內(nèi)存分配大小。
在一個實施例中,可將被測進程啟動時內(nèi)存分配信息中的內(nèi)存分配地址和退出時的內(nèi)存分配信息中的內(nèi)存分配地址進行比較,判斷被測進程退出時內(nèi)存分配信息中比被測進程啟動時內(nèi)存分配信息中多的內(nèi)存地址,則多的內(nèi)存地址為內(nèi)存泄漏地址,再得出內(nèi)存泄漏大小。
在另一個實施例中,可將被測進程啟動時內(nèi)存分配信息的函數(shù)堆棧和退出時的內(nèi)存分配信息中的函數(shù)堆棧進行比較,判斷被測進程退出時內(nèi)存分配信息中比被測進程啟動時內(nèi)存分配信息中多的函數(shù)堆棧,多的函數(shù)堆棧為函數(shù)堆棧內(nèi)存泄漏。
在一個實施例中,對多的函數(shù)堆棧按照對應(yīng)的函數(shù)地址大小進行排序,再對排序后的函數(shù)堆棧進行分類統(tǒng)計,得出函數(shù)堆棧內(nèi)存泄漏次數(shù)和函數(shù)內(nèi)存泄漏大小。
具體地,將多的函數(shù)堆棧進行分類,統(tǒng)計同一類的函數(shù)堆棧的泄漏次數(shù),并計算出所有函數(shù)堆棧內(nèi)存泄漏大小。
采用函數(shù)堆棧比較實際是一組數(shù)的比較,只有組內(nèi)每一個數(shù)都相等才算相同的函數(shù)堆棧,判斷兩個函數(shù)堆棧是否相等需要每個數(shù)都比較,大量堆棧查找的時候比較耗時,采用給函數(shù)堆棧排序,可將函數(shù)堆棧按照函數(shù)地址從大到小排序,或從小到大排序。排序處理后的函數(shù)堆棧通過使用std::set數(shù)據(jù)結(jié)構(gòu)實現(xiàn)紅黑樹管理,使查找時間復(fù)雜度降為O(lgn),極大地縮短了查找時間。
此外,還可統(tǒng)計出內(nèi)存泄漏的代碼行、嚴重程度、內(nèi)存分配的函數(shù)堆棧的變化趨勢等,通過函數(shù)堆棧的變化趨勢更好的定位內(nèi)存泄漏問題。
上述內(nèi)存泄漏檢測方法,通過在被測進程啟動時加載內(nèi)存監(jiān)控動態(tài)鏈接庫,通過內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù),收集被測進程啟動時的內(nèi)存分配信息和退出后的內(nèi)存分配信息,通過比較被測進程啟動時和退出時內(nèi)存分配信息,得出內(nèi)存泄漏信息,監(jiān)控了被測進程從啟動開始到退出的整個過程中的內(nèi)存分配信息,監(jiān)控的時間點精確,得到的數(shù)據(jù)全面,且統(tǒng)計出來的結(jié)果是始終沒有釋放的,則得出的內(nèi)存泄漏信息更加準確。
在一個實施例中,上述內(nèi)存泄漏檢測方法還包括:通過掛鉤函數(shù)調(diào)用該內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口,收集被測進程啟動后的內(nèi)存監(jiān)控信息;將該內(nèi)存監(jiān)控信息發(fā)送給數(shù)據(jù)處理進程,由該數(shù)據(jù)處理進程對該內(nèi)存監(jiān)控信息進行處理。
具體地,內(nèi)存監(jiān)控信息可為內(nèi)存分配信息或內(nèi)存釋放信息。內(nèi)存分配信息可包括內(nèi)存分配地址、內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配地址和內(nèi)存分配大小。內(nèi)存釋放信息可包括內(nèi)存釋放地址和/或內(nèi)存釋放的函數(shù)堆棧等。
數(shù)據(jù)處理進程對內(nèi)存監(jiān)控信息進行處理,收集到的內(nèi)存監(jiān)控信息主要是兩 種,一種是分配內(nèi)存,一個是釋放內(nèi)存。分配內(nèi)存時,記錄內(nèi)存分配信息,釋放內(nèi)存時,刪除記錄的內(nèi)存分配信息,如此統(tǒng)計得到的數(shù)據(jù)就是當前分配未釋放的內(nèi)存。
數(shù)據(jù)處理進程對內(nèi)存監(jiān)控信息進行處理,記錄的數(shù)據(jù)結(jié)構(gòu)可采用std::map,因map是紅黑樹實現(xiàn)的,適合做頻繁的查找、插入和刪除操作,這三種操作的時間復(fù)雜度都是O(lgn)。具體的數(shù)據(jù)結(jié)構(gòu)申明如下:
其中,map的鍵值(key)是分配內(nèi)存的地址。
通過比較兩個記錄點的內(nèi)存分配信息,分析出在這兩個時間點之間新分配出來且沒有釋放的內(nèi)存,內(nèi)存泄漏在其中。本實施例中測試所用的時間點是被測進程啟動時和被測進程退出后,這樣統(tǒng)計出來的結(jié)果是始終沒有釋放的,可以認定就是內(nèi)存泄漏,準確率很高。
因數(shù)據(jù)收集與處理都寫在內(nèi)存動態(tài)鏈接庫中,但由于數(shù)據(jù)處理耗時較多,可能導(dǎo)致進程變得嚴重卡頓,將收集到的數(shù)據(jù)發(fā)送給另一個進程處理和輸出結(jié)果,可減輕被測進程的負擔,避免出現(xiàn)卡頓,且能提高數(shù)據(jù)處理效率。
圖4為一個實施例中將內(nèi)存監(jiān)控信息發(fā)送給數(shù)據(jù)處理進程,由該數(shù)據(jù)處理進程對該內(nèi)存監(jiān)控信息進行處理的具體流程圖。如圖4所示,將內(nèi)存監(jiān)控信息發(fā)送給數(shù)據(jù)處理進程,由該數(shù)據(jù)處理進程對該內(nèi)存監(jiān)控信息進行處理的步驟包括:
步驟402,將該內(nèi)存監(jiān)控信息寫入共享內(nèi)存中。
步驟404,通過該數(shù)據(jù)處理進程的監(jiān)控線程讀取該共享內(nèi)存中的內(nèi)存監(jiān)控信息,并存入該數(shù)據(jù)處理進程的緩存中。
步驟406,通過該數(shù)據(jù)處理進程的分配線程從該緩存中取出內(nèi)存監(jiān)控信息, 并分配給該數(shù)據(jù)處理進程的處理線程進行處理。
具體地的,處理線程可采用多個,如5個、8個等。對于四核以下的中央處理器可相應(yīng)的減少處理線程數(shù)。本實施例中,采用5個處理線程,采用多個處理線程可提高處理效率。
步驟408,通過該數(shù)據(jù)處理進程的刷新線程對該被測進程的內(nèi)存監(jiān)控信息處理得到的內(nèi)存分配信息進行刷新。
刷新線程主要用于解析函數(shù)堆棧中的函數(shù)名和函數(shù)所在的模塊名等。
被測進程將收集的內(nèi)存監(jiān)控信息發(fā)送給數(shù)據(jù)處理進程,涉及到進程間通信,可采用共享內(nèi)存的方式實現(xiàn)數(shù)據(jù)的傳輸,采用共享內(nèi)存?zhèn)鬏斔俣瓤?、不易出錯。
圖5A為被測進程與數(shù)據(jù)處理進程傳輸數(shù)據(jù)的示意圖。如圖5A所示,被測進程中注入內(nèi)存監(jiān)控動態(tài)鏈接庫,調(diào)用malloc/free函數(shù)、收集相關(guān)數(shù)據(jù)、存儲收集的數(shù)據(jù),將存儲的數(shù)據(jù)傳輸給數(shù)據(jù)處理進程,數(shù)據(jù)處理進程進行數(shù)據(jù)存儲及處理、泄漏過濾與分析、內(nèi)存泄漏結(jié)果輸出、過濾設(shè)置、監(jiān)控內(nèi)核設(shè)置等。
圖5B為進程間傳輸數(shù)據(jù)的過程示意圖。如圖5B所示,被測進程收集到內(nèi)存分配和釋放操作,內(nèi)存監(jiān)控動態(tài)鏈接庫就會將收集的數(shù)據(jù)寫入到共享內(nèi)存中,數(shù)據(jù)處理進程(如TMemAnalyzer.exe)中的監(jiān)控線程,發(fā)現(xiàn)共享內(nèi)存中有數(shù)據(jù)就會讀取出來。
圖6為數(shù)據(jù)緩存示意圖。如圖6所示,在數(shù)據(jù)處理進程中增加緩存,用來暫時存放被測進程發(fā)送過來的數(shù)據(jù)(即監(jiān)控線程從共享內(nèi)存中讀取出來的數(shù)據(jù)),將原來數(shù)據(jù)收到一個處理一個的同步模式改為數(shù)據(jù)收集與數(shù)據(jù)處理分開的異步模式,數(shù)據(jù)處理對數(shù)據(jù)的收集不會造成太大影響,則被測進程收集到數(shù)據(jù)就可以發(fā)送給數(shù)據(jù)處理進程,可避免被測進程傳輸數(shù)據(jù)慢而卡頓。緩存的數(shù)據(jù)結(jié)構(gòu)是一個先進先出的隊列,可以保證數(shù)據(jù)處理的順序正確。
由于malloc和free在數(shù)據(jù)處理階段是兩個互逆的過程(malloc插入數(shù)據(jù),free刪除數(shù)據(jù)),如果在數(shù)據(jù)處理階段之前能找到對應(yīng)的malloc和free數(shù)據(jù)(對應(yīng)是指同一內(nèi)存地址),這兩個互逆的操作就能省去,提高效率,為此在緩存中加入了一個高速緩存(cache)。每當一個free數(shù)據(jù)進入緩存時從高速緩存中查找對應(yīng)的malloc數(shù)據(jù),如果找到對應(yīng)的malloc數(shù)據(jù),則刪除free數(shù)據(jù)及對應(yīng)的 malloc數(shù)據(jù)。高速緩存的大小可根據(jù)需要設(shè)定,如可為64個數(shù)據(jù)大小、128個數(shù)據(jù)大小、256個數(shù)據(jù)大小等。采用128個數(shù)據(jù)大小的高速緩存,可避免容易過大每次查找耗時,以及容量過小命中率下降的問題。
在一個實施例中,上述內(nèi)存泄漏方法還包括:當該內(nèi)存監(jiān)控信息為內(nèi)存釋放信息時,根據(jù)該內(nèi)存釋放信息從該數(shù)據(jù)處理進程的高速緩存中查找是否存在對應(yīng)的內(nèi)存分配信息,若是,則刪除該內(nèi)存釋放信息及對應(yīng)的內(nèi)存分配信息,若否,則從緩存中查找是否存在對應(yīng)的內(nèi)存分配信息,若存在則刪除該內(nèi)存釋放信息及對應(yīng)的內(nèi)存分配信息。
圖7為高速緩存機制示意圖。如圖7所示,被測進程收集的數(shù)據(jù)同步寫入共享內(nèi)存中,然后數(shù)據(jù)處理進程從共享內(nèi)存中讀取數(shù)據(jù)并暫存到緩存中,讀取的數(shù)據(jù)為內(nèi)存釋放信息,則從自身緩存中的高速緩存中查找是否存在對應(yīng)的內(nèi)存分配信息,若存在,則刪除該內(nèi)存釋放信息及對應(yīng)的內(nèi)存分配信息,若不存在,則從緩存中查找是否存在對應(yīng)的內(nèi)存分配信息,若存在則刪除該內(nèi)存釋放信息及對應(yīng)的內(nèi)存分配信息。
為了獲取某個時刻的內(nèi)存分配信息,可使用內(nèi)存快照。內(nèi)存快照是在某個時刻malloc分配了而一直沒有調(diào)用free進行釋放的內(nèi)存的集合。在整個應(yīng)用程序運行的生命周期中,每個時刻的內(nèi)存快照基本都會有所變化,因為隨著應(yīng)用程序不斷被使用者不斷的操作,內(nèi)存一直在發(fā)生著變化。獲取到每個時刻的內(nèi)存快照,可以知道兩個內(nèi)存快照之間發(fā)生了哪些內(nèi)存操作,即兩個內(nèi)存快照之間發(fā)生了內(nèi)存泄漏,通過兩個內(nèi)存快照的比對得到內(nèi)存泄漏的內(nèi)存地址。
圖8為內(nèi)存快照中內(nèi)存地址比較示意圖。如圖8所示,在功能開始的時候采集快照1,功能結(jié)束的時候采集快照2,經(jīng)過這個過程發(fā)現(xiàn)快照1的0x2進行了釋放操作,所以在快照2中已經(jīng)不存在,0x1依然在快照2中存在,則說明0x1沒有被釋放,0x3和0x4則是在快照2中才有,則說明0x3和0x4內(nèi)存塊是在該功能中分配出來的,且功能結(jié)束后還沒有及時釋放,則這兩個內(nèi)存塊為泄漏內(nèi)存塊。
圖9為內(nèi)存快照中采用函數(shù)堆棧比較的示意圖。如圖9所示,在功能開始 的時候采集快照1,功能結(jié)束的時候采集快照2,經(jīng)過這個過程發(fā)現(xiàn),進入功能后,釋放了前序場景不使用的內(nèi)存塊,即將快照1的0x2進行了釋放操作,0x1依然在快照2中存在,則說明0x1沒有被釋放,0x3和0x4是離開功能后又回到前序場景界面,程序又分配了相關(guān)內(nèi)存塊,在快照1中是有這兩內(nèi)存塊地址對應(yīng)的函數(shù)堆棧的。0x5是快照2中才有的,進入功能后又分配的相關(guān)內(nèi)存塊,且功能結(jié)束后還沒有及時釋放,則內(nèi)存塊0x5為泄漏的堆棧。
下面結(jié)合具體的應(yīng)用場景說明本發(fā)明的內(nèi)存泄漏檢測方法的過程。以游戲程序中,玩家從一個場景進入另一個場景,在另一個場景結(jié)束后重返原來的場景,其內(nèi)存泄漏檢測包括:
(a1)在進入一次被測場景后退出到前序場景開始收集第一內(nèi)存快照,該第一內(nèi)存快照記錄當前時刻的內(nèi)存分配信息;
(a2)在再次進入到被測場景后退出到前序場景開始收集第二內(nèi)存快照,該第二內(nèi)存快照記錄當前時刻的內(nèi)存分配信息;
(a3)將第一內(nèi)存快照記錄的內(nèi)存分配信息及第二內(nèi)存快照記錄的內(nèi)存分配信息進行比較,得出被測場景的內(nèi)存泄漏信息。
采用a1到a3步驟,時間點可由玩家設(shè)置,滿足玩家的個性化需求。
或者,其內(nèi)存泄漏檢測包括:
(b1)在游戲程序啟動時收集收集第一內(nèi)存快照,該第一內(nèi)存快照記錄當前時刻的內(nèi)存分配信息;
(b2)在游戲程序退出時收集第二內(nèi)存快照,該第二內(nèi)存快照記錄當前時刻的內(nèi)存分配信息;
(b3)將第一內(nèi)存快照記錄的內(nèi)存分配信息及第二內(nèi)存快照記錄的內(nèi)存分配信息進行比較,得出被測場景的內(nèi)存泄漏信息。
采用b1到b3步驟,采用的是游戲程序從啟動到退出后收集的兩個快照,比較這兩個快照得出的泄漏更加準確。
內(nèi)存分配信息包括內(nèi)存分配地址、內(nèi)存分配大小和內(nèi)存分配函數(shù)堆棧。
將第一內(nèi)存快照記錄的內(nèi)存分配信息及第二內(nèi)存快照記錄的內(nèi)存分配信息進行比較的步驟包括:將該第一內(nèi)存快照記錄的內(nèi)存分配信息中的函數(shù)堆棧和 第二內(nèi)存快照記錄的內(nèi)存分配信息中的函數(shù)堆棧進行比較,判斷該第二內(nèi)存快照記錄的內(nèi)存分配信息中比該第一內(nèi)存快照記錄的內(nèi)存分配信息中多的函數(shù)堆棧,則多的函數(shù)堆棧為函數(shù)堆棧內(nèi)存泄漏。
進一步的,對多的函數(shù)堆棧按照對應(yīng)的函數(shù)地址大小進行排序,再對排序后的函數(shù)堆棧進行分類統(tǒng)計,得出函數(shù)堆棧內(nèi)存泄漏次數(shù)和函數(shù)內(nèi)存泄漏大小。
具體地,將函數(shù)堆棧進行分類,統(tǒng)計同一類的函數(shù)堆棧的泄漏次數(shù),并計算出所有函數(shù)堆棧內(nèi)存泄漏大小。
采用函數(shù)堆棧比較實際是一組數(shù)的比較,只有組內(nèi)每一個數(shù)都相等才算相同的函數(shù)堆棧,判斷兩個函數(shù)堆棧是否相等需要每個數(shù)都比較,大量堆棧查找的時候比較耗時,采用給函數(shù)堆棧排序,可將函數(shù)堆棧按照函數(shù)地址從大到小排序,或從小到大排序。排序處理后的函數(shù)堆棧通過使用std::set數(shù)據(jù)結(jié)構(gòu)實現(xiàn)紅黑樹管理,使查找時間復(fù)雜度降為O(lgn),極大地縮短了查找時間。
通過上述內(nèi)存泄漏檢測方法把內(nèi)存泄漏信息詳細的統(tǒng)計出來,包括泄漏的額函數(shù)堆棧(可詳細到代碼行)、大小、次數(shù)。因malloc/free除了程序員本身使用外,C運行時庫的函數(shù)也會大量使用,比如fopen_s,下面是其調(diào)用堆棧。
.exe!malloc(unsigned int size=24)Line87
.exe!_malloc_crt(unsigned int cb=24)Line44
.exe!_mtinitlocknum(int locknum=19)Line274
.exe!_getstream()Line71
.exe!_fsopen(const char *file=0x00546244,const char* mode=0x00546240,int shflag=128)Line61
.exe!fopen_s(_iobuf**pfile=0x001df994,const char*file=0x00546244,const char*mode=0x00546240)Line160
.exe!main(int argc=1,char**argv=0x00662b98)Line32
為此,將內(nèi)存泄露信息通過關(guān)鍵字進行過濾。關(guān)鍵字可為預(yù)先設(shè)定的關(guān)鍵字。通過關(guān)鍵字篩選出匹配的內(nèi)存泄露信息進行展示。
上述內(nèi)存泄露檢測方法還包括:將堆棧的泄露嚴重程度按照從大到小進行排序,將泄露嚴重程度排序在前的預(yù)定數(shù)量的堆棧展示出來。
泄露嚴重程度是指泄露程度大于預(yù)設(shè)的百分比。例如同一堆棧泄露大小大于第一預(yù)設(shè)值;同一堆棧泄露次數(shù)大于第二預(yù)設(shè)值;同一堆棧根據(jù)時間軸泄露大小呈上升趨勢,上升趨勢超過第三預(yù)設(shè)值,如30%;同一堆棧中分配相同大小內(nèi)存塊占總分配塊的占比程度大于第四預(yù)設(shè)值,如50%。
在一個實施例中,上述內(nèi)存泄露檢測方法還包括:將每個堆棧的變化曲線圖展示出來,讓開發(fā)人員更加準確的判斷泄露過程。圖10為一個堆棧的變化曲線圖。如圖10所示,每隔預(yù)定間隔時間的堆棧泄露的次數(shù),橫坐標為時間,單位為秒,縱坐標為泄露次數(shù)。
在一個實施例中,上述內(nèi)存泄露檢測方法還包括:提供用戶交互界面,并在用戶交互界面上設(shè)置觸發(fā)控件。通過用戶交互界面上的觸發(fā)控件,可完成內(nèi)存泄露檢測,不需要用戶輸入不同的命令,操作簡單。
上述內(nèi)存泄露檢測方法可應(yīng)用于任意應(yīng)用程序,對任何應(yīng)用程序的性能沒有影響,采用系統(tǒng)API層及標準庫層靈活配置的方式進行hook,加上過濾策略及嚴重程度定義,提高了檢測結(jié)果的準確性和可讀性,可兼顧游戲程序及其他應(yīng)用程序,不需代碼,可一次性檢測,及對單個場景分析。
上述內(nèi)存泄露檢測方法應(yīng)用于《鐵騎》,在客戶端性能測試過程中發(fā)現(xiàn)場景(64個機器人醫(yī)師在江陵城內(nèi)反復(fù)放置香爐15分鐘,完成后自動退出)存在明顯的內(nèi)存泄露。分析結(jié)果:在進入和退出江陵城前后各截取兩個快照,通過對比,在整個15分鐘的測試過程中共泄露335.8M(兆),過了3分鐘左右內(nèi)存釋放了290.5M,直至退出該場景前內(nèi)存未發(fā)生變化,也就是退出場景前造成了45.3M的內(nèi)存泄露。在測試中,有216個相關(guān)堆棧,共調(diào)用7023次,泄露47536935字節(jié)。
上述內(nèi)存泄露檢測方法應(yīng)用于《怪物獵人》,在測試過程中內(nèi)存泄露最明顯的可以通過內(nèi)存管理器看出存在內(nèi)存泄露。分析結(jié)果:通過分析這類泄露來自程序中的flash文件的泄露,目前scaleform的泄露都是屬于這類,其調(diào)用過程為:引擎中在flashplayer instance.cpp中調(diào)用主swf文件,swf文件中調(diào)用scaleform。因此與UI相關(guān)的swf中有內(nèi)存泄露,堆棧都會調(diào)用到scaleform中去。
圖11為一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖。如圖11所示,一種內(nèi)存泄漏檢測裝置,對應(yīng)于內(nèi)存泄露檢測方法所構(gòu)建的功能模塊架構(gòu),描述不詳細之處參考方法描述,包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108。其中:
加載模塊1102用于在被測進程啟動時加載預(yù)設(shè)的內(nèi)存監(jiān)控動態(tài)鏈接庫。
具體地,首先采用靜態(tài)注入的方法,在啟動被測進程前使用detours工具包中的setdll.exe修改進程的可執(zhí)行文件(.exe文件),使被測進程啟動時自動加載預(yù)設(shè)的內(nèi)存監(jiān)控動態(tài)鏈接庫(DLL,Dynamic Link Library),從而hook(掛鉤)內(nèi)存分配函數(shù)和/或windows系統(tǒng)API(Application Programming Interface,應(yīng)用程序編程接口)。
掛鉤模塊1104用于通過該內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù)或windows系統(tǒng)應(yīng)用程序編程接口。
具體地,在內(nèi)存監(jiān)控動態(tài)鏈接庫中利用微軟提供的detours庫來實現(xiàn)hook(掛鉤)C/C++標準庫中的內(nèi)存分配函數(shù)(malloc、free和realloc等)的功能?;蛘?,hook windows系統(tǒng)應(yīng)用程序編程接口,即hook更底層的HeapAlloc系列函數(shù)(包括HeapAlloc、HeapFree和HeapRealloc)或hook底層的系統(tǒng)函數(shù)(RtAllocateHeap等)。HeapAlloc函數(shù)用來在指定的堆上分配內(nèi)存,并且分配后的內(nèi)存不可移動。采用hook C/C++標準庫中的內(nèi)存分配函數(shù),能大量去掉windows系統(tǒng)函數(shù)的影響,提高結(jié)果的精確性。
此外,還可同時在hook內(nèi)存分配函數(shù)和windows系統(tǒng)應(yīng)用程序編程接口之間切換。
收集模塊1106用于通過掛鉤函數(shù)調(diào)用該內(nèi)存分配函數(shù)或windows系統(tǒng)應(yīng)用程序編程接口,收集被測進程啟動時的內(nèi)存分配信息,以及收集被測進程退出時的內(nèi)存分配信息。
具體地,內(nèi)存監(jiān)控動態(tài)鏈接庫主要監(jiān)控內(nèi)存中malloc操作、free操作,包括內(nèi)存分配的大小、內(nèi)存分配的地址、內(nèi)存釋放的地址、內(nèi)存分配的函數(shù)堆棧等。hook函數(shù)調(diào)用內(nèi)存分配函數(shù)malloc或free,通過記錄malloc操作和free操作,從而收集被測進程啟動時的內(nèi)存分配信息。該內(nèi)存分配信息可包括內(nèi)存分 配地址、內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配地址和內(nèi)存分配大小。
比較模塊1108用于對該被測進程啟動時的內(nèi)存分配信息及退出時的內(nèi)存分配信息進行比較得出內(nèi)存泄漏信息。
具體地,該內(nèi)存分配信息可包括內(nèi)存分配地址、內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配大小和內(nèi)存分配的函數(shù)堆棧,或者包括內(nèi)存分配地址和內(nèi)存分配大小。
在一個實施例中,比較模塊1108可將被測進程啟動時內(nèi)存分配信息中的內(nèi)存分配地址和退出時的內(nèi)存分配信息中的內(nèi)存分配地址進行比較,判斷被測進程退出時內(nèi)存分配信息中比被測進程啟動時內(nèi)存分配信息中多的內(nèi)存地址,則多的內(nèi)存地址為內(nèi)存泄漏地址,再得出內(nèi)存泄漏大小。
在另一個實施例中,比較模塊1108可將被測進程啟動時內(nèi)存分配信息的函數(shù)堆棧和退出時的內(nèi)存分配信息中的函數(shù)堆棧進行比較,判斷被測進程退出時內(nèi)存分配信息中比被測進程啟動時內(nèi)存分配信息中多的函數(shù)堆棧,多的函數(shù)堆棧為函數(shù)堆棧內(nèi)存泄漏。
圖12為另一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖。如圖12所示,一種內(nèi)存泄漏檢測裝置,除了包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108,還包括第一統(tǒng)計模塊1110。其中:
第一統(tǒng)計模塊1110用于對多的函數(shù)堆棧按照對應(yīng)的函數(shù)地址大小進行排序,再對排序后的函數(shù)堆棧進行分類統(tǒng)計,得出函數(shù)堆棧內(nèi)存泄漏次數(shù)和函數(shù)內(nèi)存泄漏大小。
具體地,將函數(shù)堆棧進行分類,統(tǒng)計同一類的函數(shù)堆棧的泄漏次數(shù),并計算出所有函數(shù)堆棧內(nèi)存泄漏大小。
采用函數(shù)堆棧比較實際是一組數(shù)的比較,只有組內(nèi)每一個數(shù)都相等才算相同的函數(shù)堆棧,判斷兩個函數(shù)堆棧是否相等需要每個數(shù)都比較,大量堆棧查找的時候比較耗時,采用給函數(shù)堆棧排序,可將函數(shù)堆棧按照函數(shù)地址從大到小排序,或從小到大排序。排序處理后的函數(shù)堆棧通過使用std::set數(shù)據(jù)結(jié)構(gòu)實現(xiàn)紅黑樹管理,使查找時間復(fù)雜度降為O(lgn),極大地縮短了查找時間。
此外,還可統(tǒng)計出內(nèi)存泄漏的代碼行、嚴重程度、內(nèi)存分配的函數(shù)堆棧的變化趨勢等,通過函數(shù)堆棧的變化趨勢更好的定位內(nèi)存泄漏問題。
上述內(nèi)存泄漏檢測裝置,通過在被測進程啟動時加載內(nèi)存監(jiān)控動態(tài)鏈接庫,通過內(nèi)存監(jiān)控動態(tài)鏈接庫掛鉤內(nèi)存分配函數(shù),收集被測進程啟動時的內(nèi)存分配信息和退出后的內(nèi)存分配信息,通過比較被測進程啟動時和退出時內(nèi)存分配信息,得出內(nèi)存泄漏信息,監(jiān)控了被測進程從啟動開始到退出的整個過程中的內(nèi)存分配信息,監(jiān)控的時間點精確,得到的數(shù)據(jù)全面,且統(tǒng)計出來的結(jié)果是始終沒有釋放的,則得出的內(nèi)存泄漏信息更加準確。
在一個實施例中,收集模塊1106還用于通過掛鉤函數(shù)調(diào)用該內(nèi)存分配函數(shù)和/或windows系統(tǒng)應(yīng)用程序編程接口,收集被測進程啟動后的內(nèi)存監(jiān)控信息。
圖13為另一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖。如圖13所示,一種內(nèi)存泄漏檢測裝置,除了包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108,還包括傳輸模塊1112、讀取模塊1114、存儲模塊1116、取出模塊1118、分配模塊1120、刷新模塊1122、查找模塊1124、刪除模塊1126。
其中:傳輸模塊1112用于將該內(nèi)存監(jiān)控信息發(fā)送給數(shù)據(jù)處理進程,由該數(shù)據(jù)處理進程對該內(nèi)存監(jiān)控信息進行處理。
傳輸模塊1112還用于將該內(nèi)存監(jiān)控信息寫入共享內(nèi)存中。
讀取模塊1114用于通過該數(shù)據(jù)處理進程的監(jiān)控線程讀取該共享內(nèi)存中的內(nèi)存監(jiān)控信息。
存儲模塊1116用于將讀取的內(nèi)存監(jiān)控信息存入該數(shù)據(jù)處理進程的緩存中。
取出模塊1118用于通過該數(shù)據(jù)處理進程的分配線程從該緩存中取出內(nèi)存監(jiān)控信息。
分配模塊1120用于分配給該數(shù)據(jù)處理進程的處理線程進行處理。
刷新模塊1122用于通過該數(shù)據(jù)處理進程的刷新線程對該被測進程的內(nèi)存監(jiān)控信息處理得到的內(nèi)存分配信息進行刷新。
該內(nèi)存監(jiān)控信息為內(nèi)存分配信息或內(nèi)存釋放信息;
查找模塊1124用于當該內(nèi)存監(jiān)控信息為內(nèi)存釋放信息時,根據(jù)該內(nèi)存釋放 信息從該數(shù)據(jù)處理進程的高速緩存中查找是否存在對應(yīng)的內(nèi)存分配信息。
刪除模塊1126用于若該數(shù)據(jù)處理進程的高速緩存中存在對應(yīng)的內(nèi)存分配信息,則刪除該內(nèi)存釋放信息及對應(yīng)的內(nèi)存分配信息。
以游戲程序中,玩家從一個場景進入另一個場景,在另一個場景結(jié)束后重返原來的場景,其內(nèi)存泄漏檢測包括:
收集模塊1106還用于在進入一次被測場景后退出到前序場景開始收集第一內(nèi)存快照,該第一內(nèi)存快照記錄當前時刻的內(nèi)存分配信息,以及在再次進入到被測場景后退出到前序場景開始收集第二內(nèi)存快照,該第二內(nèi)存快照記錄當前時刻的內(nèi)存分配信息;
比較模塊1108還用于將第一內(nèi)存快照記錄的內(nèi)存分配信息及第二內(nèi)存快照記錄的內(nèi)存分配信息進行比較,得出被測場景的內(nèi)存泄漏信息。
或者,收集模塊1106還用于在游戲程序啟動時收集第一內(nèi)存快照,該第一內(nèi)存快照記錄當前時刻的內(nèi)存分配信息,以及在游戲程序退出時收集第二內(nèi)存快照,該第二內(nèi)存快照記錄當前時刻的內(nèi)存分配信息;
比較模塊1108還用于將第一內(nèi)存快照記錄的內(nèi)存分配信息及第二內(nèi)存快照記錄的內(nèi)存分配信息進行比較,得出被測場景的內(nèi)存泄漏信息。
該內(nèi)存分配信息包括內(nèi)存分配未釋放的地址、內(nèi)存分配未釋放的大小和內(nèi)存分配未釋放的函數(shù)堆棧;
比較模塊1108還用于將該第一內(nèi)存快照記錄的內(nèi)存分配信息中的函數(shù)堆棧和第二內(nèi)存快照記錄的內(nèi)存分配信息中的函數(shù)堆棧進行比較,判斷第二內(nèi)存快照記錄的內(nèi)存分配信息中比第一內(nèi)存快照記錄的內(nèi)存分配信息中多的函數(shù)堆棧,則多的函數(shù)堆棧為函數(shù)堆棧內(nèi)存泄漏。
圖14為另一個實施例中內(nèi)存泄露檢測裝置的結(jié)構(gòu)框圖。如圖14所示,一種內(nèi)存泄漏檢測裝置,除了包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108,還包括第二統(tǒng)計模塊1128。
第二統(tǒng)計模塊1128用于對多的函數(shù)堆棧按照對應(yīng)的函數(shù)地址大小進行排序,再對排序后的函數(shù)堆棧進行分類統(tǒng)計,得出函數(shù)堆棧內(nèi)存泄漏次數(shù)和函數(shù)內(nèi)存泄漏大小。
具體地,將函數(shù)堆棧進行分類,統(tǒng)計同一類的函數(shù)堆棧的泄漏次數(shù),并計算出所有函數(shù)堆棧內(nèi)存泄漏大小。
在其他實施例中,內(nèi)存泄露裝置可包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108、第一統(tǒng)計模塊1110、傳輸模塊1112、讀取模塊1114、存儲模塊1116、取出模塊1118、分配模塊1120、刷新模塊1122、查找模塊1124、刪除模塊1126、第二統(tǒng)計模塊1128任意可能的組合。
本領(lǐng)域普通技術(shù)人員可以理解實現(xiàn)上述實施例方法中的全部或部分流程,是可以通過計算機程序來指令相關(guān)的硬件來完成,所述的程序可存儲于一非易失性計算機可讀取存儲介質(zhì)中,該程序在執(zhí)行時,可包括如上述各方法的實施例的流程。其中,所述的存儲介質(zhì)可為磁碟、光盤、只讀存儲記憶體(Read-Only Memory,ROM)等。
以上所述實施例僅表達了本發(fā)明的幾種實施方式,其描述較為具體和詳細,但并不能因此而理解為對本發(fā)明專利范圍的限制。應(yīng)當指出的是,對于本領(lǐng)域的普通技術(shù)人員來說,在不脫離本發(fā)明構(gòu)思的前提下,還可以做出若干變形和改進,這些都屬于本發(fā)明的保護范圍。因此,本發(fā)明專利的保護范圍應(yīng)以所附權(quán)利要求為準。