<listing id="vjp15"></listing><menuitem id="vjp15"></menuitem><var id="vjp15"></var><cite id="vjp15"></cite>
<var id="vjp15"></var><cite id="vjp15"><video id="vjp15"><menuitem id="vjp15"></menuitem></video></cite>
<cite id="vjp15"></cite>
<var id="vjp15"><strike id="vjp15"><listing id="vjp15"></listing></strike></var>
<var id="vjp15"><strike id="vjp15"><listing id="vjp15"></listing></strike></var>
<menuitem id="vjp15"><strike id="vjp15"></strike></menuitem>
<cite id="vjp15"></cite>
<var id="vjp15"><strike id="vjp15"></strike></var>
<var id="vjp15"></var>
<var id="vjp15"></var>
<var id="vjp15"><video id="vjp15"><thead id="vjp15"></thead></video></var>
<menuitem id="vjp15"></menuitem><cite id="vjp15"><video id="vjp15"></video></cite>
<var id="vjp15"></var><cite id="vjp15"><video id="vjp15"><thead id="vjp15"></thead></video></cite>
<var id="vjp15"></var>
<var id="vjp15"></var>
<menuitem id="vjp15"><span id="vjp15"><thead id="vjp15"></thead></span></menuitem>
<cite id="vjp15"><video id="vjp15"></video></cite>
<menuitem id="vjp15"></menuitem>

內存泄漏檢測方法和裝置與流程

文檔序號:11063415閱讀:690來源:國知局
內存泄漏檢測方法和裝置與制造工藝

本發明涉及內存檢測領域,特別是涉及一種內存泄漏檢測方法和裝置。



背景技術:

內存泄漏是指堆內存的泄漏。堆內存是指程序從堆中分配的,大小任意的,使用完后必須顯示釋放的內存。應用程序一般使用malloc、realloc、new等函數從堆中分配到一塊內存,使用完后,程序必須負責相應的調用free或delete釋放該內存塊,否則,這塊內存就不能被再次使用,也就是這塊內存泄漏了。

在常規的客戶端性能專項測試中,內存使用情況是重點關注的一個指標。Windows調試工具集(the Debugging Tools for Windows)中的UMDH工具能監控到內存泄漏的問題點,得到內存泄漏處的堆棧。UMDH監控Windows系統函數中的內存分配函數,通過統計比較使用者手動指定的開始和結束兩個時間點內存分配情況得到這兩個時間點之間的內存泄漏,然而手動指定難以精確,且得到的數據不全面。



技術實現要素:

基于此,有必要針對傳統的內存泄漏檢測手動指定時間點不夠精確且得到的數據不全面的問題,提供一種內存泄漏檢測方法,監控的時間點精確且監控的數據全面。

此外,還有必要提供一種內存泄漏檢測裝置,監控的時間點精確且監控的數據全面。

一種內存泄漏檢測方法,包括以下步驟:

在被測進程啟動時加載預設的內存監控動態鏈接庫;

通過所述內存監控動態鏈接庫掛鉤內存分配函數和/或windows系統應用程序編程接口;

通過掛鉤函數調用所述內存分配函數和/或windows系統應用程序編程接 口,收集被測進程啟動時的內存分配信息,以及收集被測進程退出時的內存分配信息;

對所述被測進程啟動時的內存分配信息及退出時的內存分配信息進行比較得出內存泄漏信息。

一種內存泄漏檢測裝置,包括:

加載模塊,用于在被測進程啟動時加載預設的內存監控動態鏈接庫;

掛鉤模塊,用于通過所述內存監控動態鏈接庫掛鉤內存分配函數和/或windows系統應用程序編程接口;

收集模塊,用于通過掛鉤函數調用所述內存分配函數和/或windows系統應用程序編程接口,收集被測進程啟動時的內存分配信息,以及收集被測進程退出時的內存分配信息;

比較模塊,用于對所述被測進程啟動時的內存分配信息及退出時的內存分配信息進行比較得出內存泄漏信息。

上述內存泄漏檢測方法和裝置,通過在被測進程啟動時加載內存監控動態鏈接庫,通過內存監控動態鏈接庫掛鉤內存分配函數,收集被測進程啟動時的內存分配信息和退出后的內存分配信息,通過比較被測進程啟動時和退出時內存分配信息,得出內存泄漏信息,監控了被測進程從啟動開始到退出的整個過程中的內存分配信息,監控的時間點精確,得到的數據全面,且統計出來的結果是始終沒有釋放的,則得出的內存泄漏信息更加準確。

附圖說明

圖1A為一個實施例中終端的內部結構示意圖;

圖1B為一個實施例中服務器的內部結構示意圖;

圖2為一個實施例中內存泄漏檢測方法的流程圖;

圖3為函數調用關系示意圖;

圖4為一個實施例中將內存監控信息發送給數據處理進程,由該數據處理進程對該內存監控信息進行處理的具體流程圖;

圖5A為被測進程與數據處理進程傳輸數據的示意圖;

圖5B為進程間傳輸數據的過程示意圖;

圖6為數據緩存示意圖;

圖7為高速緩存機制示意圖;

圖8為內存快照中內存地址比較示意圖;

圖9為內存快照中采用函數堆棧比較的示意圖;

圖10為一個堆棧的變化曲線圖;

圖11為一個實施例中內存泄露檢測裝置的結構框圖;

圖12為另一個實施例中內存泄露檢測裝置的結構框圖;

圖13為另一個實施例中內存泄露檢測裝置的結構框圖;

圖14為另一個實施例中內存泄露檢測裝置的結構框圖。

具體實施方式

為了使本發明的目的、技術方案及優點更加清楚明白,以下結合附圖及實施例,對本發明進行進一步詳細說明。應當理解,此處所描述的具體實施例僅僅用以解釋本發明,并不用于限定本發明。

可以理解,本發明所使用的術語“第一”、“第二”等可在本文中用于描述各種元件,但這些元件不受這些術語限制。這些術語僅用于將第一個元件與另一個元件區分。舉例來說,在不脫離本發明的范圍的情況下,可以將第一客戶端稱為第二客戶端,且類似地,可將第二客戶端稱為第一客戶端。第一客戶端和第二客戶端兩者都是客戶端,但其不是同一客戶端。

圖1A為一個實施例中終端的內部結構示意圖。如圖1A所示,該終端包括通過系統總線連接的處理器、存儲介質、內存、網絡接口、聲音采集裝置、顯示屏、揚聲器和輸入裝置。其中,終端的存儲介質存儲有操作系統,還包括一種內存泄漏檢測裝置,該內存泄漏檢測裝置用于實現一種內存泄漏檢測方法。該處理器用于提供計算和控制能力,支撐整個終端的運行。終端中的內存為存儲介質中的內存泄漏裝置的運行提供環境,網絡接口用于與服務器進行網絡通信,如發送游戲數據請求至服務器,接收服務器返回的游戲數據等。終端的顯示屏可以是液晶顯示屏或者電子墨水顯示屏等,輸入裝置可以是顯示屏上覆蓋的觸 摸層,也可以是終端外殼上設置的按鍵、軌跡球或觸控板,也可以是外接的鍵盤、觸控板或鼠標等。該終端可以是手機、平板電腦或者個人數字助理。本領域技術人員可以理解,圖1A中示出的結構,僅僅是與本申請方案相關的部分結構的框圖,并不構成對本申請方案所應用于其上的終端的限定,具體的終端可以包括比圖中所示更多或更少的部件,或者組合某些部件,或者具有不同的部件布置。

圖1B為一個實施例中服務器的內部結構示意圖。如圖1B所示,該服務器包括通過系統總線連接的處理器、存儲介質、內存、網絡接口、顯示屏和輸入裝置。其中,該服務器的存儲介質存儲有操作系統、數據庫和內存泄漏檢測裝置,數據庫中存儲有游戲場景數據、游戲用戶數據等,該內存泄漏裝置用于實現適用于服務器的一種內存泄漏檢測方法。該服務器的處理器用于提供計算和控制能力,支撐整個服務器的運行。該服務器的內存為存儲介質中的內存泄漏裝置的運行提供環境。該服務器的顯示屏可以是液晶顯示屏或者電子墨水顯示屏等,輸入裝置可以是顯示屏上覆蓋的觸摸層,也可以是終端外殼上設置的按鍵、軌跡球或觸控板,也可以是外接的鍵盤、觸控板或鼠標等。該服務器的網絡接口用于據以與外部的終端通過網絡連接通信,比如接收終端發送的游戲數據請求以及向終端返回游戲數據等。服務器可以用獨立的服務器或者是多個服務器組成的服務器集群來實現。本領域技術人員可以理解,圖1B中示出的結構,僅僅是與本申請方案相關的部分結構的框圖,并不構成對本申請方案所應用于其上的服務器的限定,具體的服務器可以包括比圖中所示更多或更少的部件,或者組合某些部件,或者具有不同的部件布置。

內存泄漏是指應用程序使用malloc、realloc、new等函數從堆中分配到一塊內存,使用完后,未調用free或delete函數釋放該內存塊導致的。傳統的內存泄漏檢測方法比較的是使用者指定的兩個時間點的內存泄漏情況,而有些應用程序在退出后才釋放分配的內存,導致檢測的內存泄漏數據不全面,也不準確。本發明中的內存泄漏檢測方法,通過在被測進程啟動時加載內存監控動態鏈接庫并執行其中的函數,在被測進程啟動時開始監控內存分配信息,在被測進程退出時仍然執行加載后的內存監控動態鏈接庫監控被測進程退出后的內存分配 信息,通過比較被測進程啟動時和退出時內存分配信息,得出內存泄漏信息,監控了被測進程從啟動開始到退出的整個過程中的內存分配信息,監控的時間點精確,得到的數據全面,且得出內存泄漏信息更加準確。

其中,malloc函數,即memory allocation,動態內存分配函數,若分配成功,則返回指向被分配內存的指針,否則返回空指針。

realloc函數,即reset allocation,動態內存調整函數,若重新分配成功,則返回指向被分配內存的指針,否則返回空指針。

new相當于一個函數,在內存開辟完空間后,返回這個空間的首地址。

free或delete函數,釋放內存。

內存分配信息可包括內存分配地址、內存分配大小和內存分配的函數堆棧,或者包括內存分配大小和內存分配的函數堆棧,或者包括內存分配地址和內存分配大小。

圖2為一個實施例中內存泄漏檢測方法的流程圖。如圖2所示,一種內存泄漏檢測方法,包括以下步驟:

步驟202,在被測進程啟動時加載預設的內存監控動態鏈接庫。

具體地,首先采用靜態注入的方法,在啟動被測進程前使用detours工具包中的setdll.exe修改進程的可執行文件(.exe文件),使被測進程啟動時自動加載預設的內存監控動態鏈接庫(DLL,Dynamic Link Library),從而hook(掛鉤)內存分配函數和/或windows系統API(Application Programming Interface,應用程序編程接口)。

步驟204,通過該內存監控動態鏈接庫掛鉤內存分配函數和/或windows系統應用程序編程接口。

具體地,在內存監控動態鏈接庫中利用微軟提供的detours庫來實現hook(掛鉤)C/C++標準庫中的內存分配函數(malloc、free和realloc等)的功能。或者,hook windows系統應用程序編程接口,即hook更底層的HeapAlloc系列函數(包括HeapAlloc、HeapFree和HeapRealloc)或hook底層的系統函數(RtAllocateHeap等)。HeapAlloc函數用來在指定的堆上分配內存,并且分配后的內存不可移動。采用hook C/C++標準庫中的內存分配函數,能大量去掉 windows系統函數的影響,提高結果的精確性。

此外,還可同時在hook內存分配函數和windows系統應用程序編程接口之間切換。

在對malloc/free兩個函數進行hook的過程中,可能會出現找不到地址的情況,其原因跟標準庫的鏈接方式有關系,標準庫函數既可以從一個libc*.lib靜態鏈接,也可以從一個msvcrt*.dll動態鏈接到程序中。當靜態鏈接到程序時,一個程序得到它自己私有的版本的標準庫函數;當動態鏈接程序時,一個程序共享DLL中版本的靜態標準庫函數。在獲取malloc/free地址時需進行區分。

圖3為函數調用關系示意圖。如圖3所示,new分配內存后,通過調用malloc函數、heapalloc函數收集內存分配信息。

步驟206,通過掛鉤函數調用該內存分配函數和/或windows系統應用程序編程接口,收集被測進程啟動時的內存分配信息,以及收集被測進程退出時的內存分配信息。

具體地,內存監控動態鏈接庫主要監控內存中malloc操作、free操作,包括內存分配的大小、內存分配的地址、內存釋放的地址、內存分配的函數堆棧等。hook函數調用內存分配函數malloc或free,通過記錄malloc操作和free操作,從而收集被測進程啟動時的內存分配信息。該內存分配信息可包括內存分配地址、內存分配大小和內存分配的函數堆棧,或者包括內存分配大小和內存分配的函數堆棧,或者包括內存分配地址和內存分配大小。

malloc用于收集內存分配信息。free函數用于收集內存釋放信息。內存釋放信息可包括內存釋放地址和/或內存釋放的函數堆棧等。

malloc系列函數的申明如下:

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系列函數申明中可以看出,地址和大小從函數調用的參數或返回值可以直接獲得,堆棧則需要調用dbghelp.dll中提供的函數獲取,具體方法是調用系統函數LoadLibrary()加載dbghelp.dll,調用如下:

HMODULE m_dbgHelp=LoadLibrary(“dbghelp.dll”);

然后通過函數GetProcAddress()獲取DLL中具體函數地址。

具體有兩個函數可以獲取堆棧,CaptureStackBackTrace()和StackWalk64()。兩者有些區別,CaptureStackBackTrace是windows系統函數,調用一次可獲取全部堆棧,速度快;StackWalk64調用一次只能獲取一層堆棧,使用時需要循環調用才能獲取全部堆棧,速度慢,能獲取的堆棧較多。

例如,在funcB中調用CaptureStackBackTrace(),獲得的堆棧為:

funcB()

funcA()

main()

若在funcB中調用StackWalk64(),只能獲得funcB(),需要再調用一次獲得funcA(),循環調用,直到不能再獲取堆棧。

在個實施例中,上述內存泄漏檢測方法還包括:采用堆棧全局獲取函數(如CaptureStackBackTrace)獲取堆棧,如果獲取失敗,則再采用堆棧局部獲取函數(如StackWalk64)獲取一次。

步驟208,對該被測進程啟動時的內存分配信息及退出時的內存分配信息進行比較得出內存泄漏信息。

具體地,該內存分配信息可包括內存分配地址、內存分配大小和內存分配的函數堆棧,或者包括內存分配大小和內存分配的函數堆棧,或者包括內存分配地址和內存分配大小。

在一個實施例中,可將被測進程啟動時內存分配信息中的內存分配地址和退出時的內存分配信息中的內存分配地址進行比較,判斷被測進程退出時內存分配信息中比被測進程啟動時內存分配信息中多的內存地址,則多的內存地址為內存泄漏地址,再得出內存泄漏大小。

在另一個實施例中,可將被測進程啟動時內存分配信息的函數堆棧和退出時的內存分配信息中的函數堆棧進行比較,判斷被測進程退出時內存分配信息中比被測進程啟動時內存分配信息中多的函數堆棧,多的函數堆棧為函數堆棧內存泄漏。

在一個實施例中,對多的函數堆棧按照對應的函數地址大小進行排序,再對排序后的函數堆棧進行分類統計,得出函數堆棧內存泄漏次數和函數內存泄漏大小。

具體地,將多的函數堆棧進行分類,統計同一類的函數堆棧的泄漏次數,并計算出所有函數堆棧內存泄漏大小。

采用函數堆棧比較實際是一組數的比較,只有組內每一個數都相等才算相同的函數堆棧,判斷兩個函數堆棧是否相等需要每個數都比較,大量堆棧查找的時候比較耗時,采用給函數堆棧排序,可將函數堆棧按照函數地址從大到小排序,或從小到大排序。排序處理后的函數堆棧通過使用std::set數據結構實現紅黑樹管理,使查找時間復雜度降為O(lgn),極大地縮短了查找時間。

此外,還可統計出內存泄漏的代碼行、嚴重程度、內存分配的函數堆棧的變化趨勢等,通過函數堆棧的變化趨勢更好的定位內存泄漏問題。

上述內存泄漏檢測方法,通過在被測進程啟動時加載內存監控動態鏈接庫,通過內存監控動態鏈接庫掛鉤內存分配函數,收集被測進程啟動時的內存分配信息和退出后的內存分配信息,通過比較被測進程啟動時和退出時內存分配信息,得出內存泄漏信息,監控了被測進程從啟動開始到退出的整個過程中的內存分配信息,監控的時間點精確,得到的數據全面,且統計出來的結果是始終沒有釋放的,則得出的內存泄漏信息更加準確。

在一個實施例中,上述內存泄漏檢測方法還包括:通過掛鉤函數調用該內存分配函數和/或windows系統應用程序編程接口,收集被測進程啟動后的內存監控信息;將該內存監控信息發送給數據處理進程,由該數據處理進程對該內存監控信息進行處理。

具體地,內存監控信息可為內存分配信息或內存釋放信息。內存分配信息可包括內存分配地址、內存分配大小和內存分配的函數堆棧,或者包括內存分配大小和內存分配的函數堆棧,或者包括內存分配地址和內存分配大小。內存釋放信息可包括內存釋放地址和/或內存釋放的函數堆棧等。

數據處理進程對內存監控信息進行處理,收集到的內存監控信息主要是兩 種,一種是分配內存,一個是釋放內存。分配內存時,記錄內存分配信息,釋放內存時,刪除記錄的內存分配信息,如此統計得到的數據就是當前分配未釋放的內存。

數據處理進程對內存監控信息進行處理,記錄的數據結構可采用std::map,因map是紅黑樹實現的,適合做頻繁的查找、插入和刪除操作,這三種操作的時間復雜度都是O(lgn)。具體的數據結構申明如下:

其中,map的鍵值(key)是分配內存的地址。

通過比較兩個記錄點的內存分配信息,分析出在這兩個時間點之間新分配出來且沒有釋放的內存,內存泄漏在其中。本實施例中測試所用的時間點是被測進程啟動時和被測進程退出后,這樣統計出來的結果是始終沒有釋放的,可以認定就是內存泄漏,準確率很高。

因數據收集與處理都寫在內存動態鏈接庫中,但由于數據處理耗時較多,可能導致進程變得嚴重卡頓,將收集到的數據發送給另一個進程處理和輸出結果,可減輕被測進程的負擔,避免出現卡頓,且能提高數據處理效率。

圖4為一個實施例中將內存監控信息發送給數據處理進程,由該數據處理進程對該內存監控信息進行處理的具體流程圖。如圖4所示,將內存監控信息發送給數據處理進程,由該數據處理進程對該內存監控信息進行處理的步驟包括:

步驟402,將該內存監控信息寫入共享內存中。

步驟404,通過該數據處理進程的監控線程讀取該共享內存中的內存監控信息,并存入該數據處理進程的緩存中。

步驟406,通過該數據處理進程的分配線程從該緩存中取出內存監控信息, 并分配給該數據處理進程的處理線程進行處理。

具體地的,處理線程可采用多個,如5個、8個等。對于四核以下的中央處理器可相應的減少處理線程數。本實施例中,采用5個處理線程,采用多個處理線程可提高處理效率。

步驟408,通過該數據處理進程的刷新線程對該被測進程的內存監控信息處理得到的內存分配信息進行刷新。

刷新線程主要用于解析函數堆棧中的函數名和函數所在的模塊名等。

被測進程將收集的內存監控信息發送給數據處理進程,涉及到進程間通信,可采用共享內存的方式實現數據的傳輸,采用共享內存傳輸速度快、不易出錯。

圖5A為被測進程與數據處理進程傳輸數據的示意圖。如圖5A所示,被測進程中注入內存監控動態鏈接庫,調用malloc/free函數、收集相關數據、存儲收集的數據,將存儲的數據傳輸給數據處理進程,數據處理進程進行數據存儲及處理、泄漏過濾與分析、內存泄漏結果輸出、過濾設置、監控內核設置等。

圖5B為進程間傳輸數據的過程示意圖。如圖5B所示,被測進程收集到內存分配和釋放操作,內存監控動態鏈接庫就會將收集的數據寫入到共享內存中,數據處理進程(如TMemAnalyzer.exe)中的監控線程,發現共享內存中有數據就會讀取出來。

圖6為數據緩存示意圖。如圖6所示,在數據處理進程中增加緩存,用來暫時存放被測進程發送過來的數據(即監控線程從共享內存中讀取出來的數據),將原來數據收到一個處理一個的同步模式改為數據收集與數據處理分開的異步模式,數據處理對數據的收集不會造成太大影響,則被測進程收集到數據就可以發送給數據處理進程,可避免被測進程傳輸數據慢而卡頓。緩存的數據結構是一個先進先出的隊列,可以保證數據處理的順序正確。

由于malloc和free在數據處理階段是兩個互逆的過程(malloc插入數據,free刪除數據),如果在數據處理階段之前能找到對應的malloc和free數據(對應是指同一內存地址),這兩個互逆的操作就能省去,提高效率,為此在緩存中加入了一個高速緩存(cache)。每當一個free數據進入緩存時從高速緩存中查找對應的malloc數據,如果找到對應的malloc數據,則刪除free數據及對應的 malloc數據。高速緩存的大小可根據需要設定,如可為64個數據大小、128個數據大小、256個數據大小等。采用128個數據大小的高速緩存,可避免容易過大每次查找耗時,以及容量過小命中率下降的問題。

在一個實施例中,上述內存泄漏方法還包括:當該內存監控信息為內存釋放信息時,根據該內存釋放信息從該數據處理進程的高速緩存中查找是否存在對應的內存分配信息,若是,則刪除該內存釋放信息及對應的內存分配信息,若否,則從緩存中查找是否存在對應的內存分配信息,若存在則刪除該內存釋放信息及對應的內存分配信息。

圖7為高速緩存機制示意圖。如圖7所示,被測進程收集的數據同步寫入共享內存中,然后數據處理進程從共享內存中讀取數據并暫存到緩存中,讀取的數據為內存釋放信息,則從自身緩存中的高速緩存中查找是否存在對應的內存分配信息,若存在,則刪除該內存釋放信息及對應的內存分配信息,若不存在,則從緩存中查找是否存在對應的內存分配信息,若存在則刪除該內存釋放信息及對應的內存分配信息。

為了獲取某個時刻的內存分配信息,可使用內存快照。內存快照是在某個時刻malloc分配了而一直沒有調用free進行釋放的內存的集合。在整個應用程序運行的生命周期中,每個時刻的內存快照基本都會有所變化,因為隨著應用程序不斷被使用者不斷的操作,內存一直在發生著變化。獲取到每個時刻的內存快照,可以知道兩個內存快照之間發生了哪些內存操作,即兩個內存快照之間發生了內存泄漏,通過兩個內存快照的比對得到內存泄漏的內存地址。

圖8為內存快照中內存地址比較示意圖。如圖8所示,在功能開始的時候采集快照1,功能結束的時候采集快照2,經過這個過程發現快照1的0x2進行了釋放操作,所以在快照2中已經不存在,0x1依然在快照2中存在,則說明0x1沒有被釋放,0x3和0x4則是在快照2中才有,則說明0x3和0x4內存塊是在該功能中分配出來的,且功能結束后還沒有及時釋放,則這兩個內存塊為泄漏內存塊。

圖9為內存快照中采用函數堆棧比較的示意圖。如圖9所示,在功能開始 的時候采集快照1,功能結束的時候采集快照2,經過這個過程發現,進入功能后,釋放了前序場景不使用的內存塊,即將快照1的0x2進行了釋放操作,0x1依然在快照2中存在,則說明0x1沒有被釋放,0x3和0x4是離開功能后又回到前序場景界面,程序又分配了相關內存塊,在快照1中是有這兩內存塊地址對應的函數堆棧的。0x5是快照2中才有的,進入功能后又分配的相關內存塊,且功能結束后還沒有及時釋放,則內存塊0x5為泄漏的堆棧。

下面結合具體的應用場景說明本發明的內存泄漏檢測方法的過程。以游戲程序中,玩家從一個場景進入另一個場景,在另一個場景結束后重返原來的場景,其內存泄漏檢測包括:

(a1)在進入一次被測場景后退出到前序場景開始收集第一內存快照,該第一內存快照記錄當前時刻的內存分配信息;

(a2)在再次進入到被測場景后退出到前序場景開始收集第二內存快照,該第二內存快照記錄當前時刻的內存分配信息;

(a3)將第一內存快照記錄的內存分配信息及第二內存快照記錄的內存分配信息進行比較,得出被測場景的內存泄漏信息。

采用a1到a3步驟,時間點可由玩家設置,滿足玩家的個性化需求。

或者,其內存泄漏檢測包括:

(b1)在游戲程序啟動時收集收集第一內存快照,該第一內存快照記錄當前時刻的內存分配信息;

(b2)在游戲程序退出時收集第二內存快照,該第二內存快照記錄當前時刻的內存分配信息;

(b3)將第一內存快照記錄的內存分配信息及第二內存快照記錄的內存分配信息進行比較,得出被測場景的內存泄漏信息。

采用b1到b3步驟,采用的是游戲程序從啟動到退出后收集的兩個快照,比較這兩個快照得出的泄漏更加準確。

內存分配信息包括內存分配地址、內存分配大小和內存分配函數堆棧。

將第一內存快照記錄的內存分配信息及第二內存快照記錄的內存分配信息進行比較的步驟包括:將該第一內存快照記錄的內存分配信息中的函數堆棧和 第二內存快照記錄的內存分配信息中的函數堆棧進行比較,判斷該第二內存快照記錄的內存分配信息中比該第一內存快照記錄的內存分配信息中多的函數堆棧,則多的函數堆棧為函數堆棧內存泄漏。

進一步的,對多的函數堆棧按照對應的函數地址大小進行排序,再對排序后的函數堆棧進行分類統計,得出函數堆棧內存泄漏次數和函數內存泄漏大小。

具體地,將函數堆棧進行分類,統計同一類的函數堆棧的泄漏次數,并計算出所有函數堆棧內存泄漏大小。

采用函數堆棧比較實際是一組數的比較,只有組內每一個數都相等才算相同的函數堆棧,判斷兩個函數堆棧是否相等需要每個數都比較,大量堆棧查找的時候比較耗時,采用給函數堆棧排序,可將函數堆棧按照函數地址從大到小排序,或從小到大排序。排序處理后的函數堆棧通過使用std::set數據結構實現紅黑樹管理,使查找時間復雜度降為O(lgn),極大地縮短了查找時間。

通過上述內存泄漏檢測方法把內存泄漏信息詳細的統計出來,包括泄漏的額函數堆棧(可詳細到代碼行)、大小、次數。因malloc/free除了程序員本身使用外,C運行時庫的函數也會大量使用,比如fopen_s,下面是其調用堆棧。

.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

為此,將內存泄露信息通過關鍵字進行過濾。關鍵字可為預先設定的關鍵字。通過關鍵字篩選出匹配的內存泄露信息進行展示。

上述內存泄露檢測方法還包括:將堆棧的泄露嚴重程度按照從大到小進行排序,將泄露嚴重程度排序在前的預定數量的堆棧展示出來。

泄露嚴重程度是指泄露程度大于預設的百分比。例如同一堆棧泄露大小大于第一預設值;同一堆棧泄露次數大于第二預設值;同一堆棧根據時間軸泄露大小呈上升趨勢,上升趨勢超過第三預設值,如30%;同一堆棧中分配相同大小內存塊占總分配塊的占比程度大于第四預設值,如50%。

在一個實施例中,上述內存泄露檢測方法還包括:將每個堆棧的變化曲線圖展示出來,讓開發人員更加準確的判斷泄露過程。圖10為一個堆棧的變化曲線圖。如圖10所示,每隔預定間隔時間的堆棧泄露的次數,橫坐標為時間,單位為秒,縱坐標為泄露次數。

在一個實施例中,上述內存泄露檢測方法還包括:提供用戶交互界面,并在用戶交互界面上設置觸發控件。通過用戶交互界面上的觸發控件,可完成內存泄露檢測,不需要用戶輸入不同的命令,操作簡單。

上述內存泄露檢測方法可應用于任意應用程序,對任何應用程序的性能沒有影響,采用系統API層及標準庫層靈活配置的方式進行hook,加上過濾策略及嚴重程度定義,提高了檢測結果的準確性和可讀性,可兼顧游戲程序及其他應用程序,不需代碼,可一次性檢測,及對單個場景分析。

上述內存泄露檢測方法應用于《鐵騎》,在客戶端性能測試過程中發現場景(64個機器人醫師在江陵城內反復放置香爐15分鐘,完成后自動退出)存在明顯的內存泄露。分析結果:在進入和退出江陵城前后各截取兩個快照,通過對比,在整個15分鐘的測試過程中共泄露335.8M(兆),過了3分鐘左右內存釋放了290.5M,直至退出該場景前內存未發生變化,也就是退出場景前造成了45.3M的內存泄露。在測試中,有216個相關堆棧,共調用7023次,泄露47536935字節。

上述內存泄露檢測方法應用于《怪物獵人》,在測試過程中內存泄露最明顯的可以通過內存管理器看出存在內存泄露。分析結果:通過分析這類泄露來自程序中的flash文件的泄露,目前scaleform的泄露都是屬于這類,其調用過程為:引擎中在flashplayer instance.cpp中調用主swf文件,swf文件中調用scaleform。因此與UI相關的swf中有內存泄露,堆棧都會調用到scaleform中去。

圖11為一個實施例中內存泄露檢測裝置的結構框圖。如圖11所示,一種內存泄漏檢測裝置,對應于內存泄露檢測方法所構建的功能模塊架構,描述不詳細之處參考方法描述,包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108。其中:

加載模塊1102用于在被測進程啟動時加載預設的內存監控動態鏈接庫。

具體地,首先采用靜態注入的方法,在啟動被測進程前使用detours工具包中的setdll.exe修改進程的可執行文件(.exe文件),使被測進程啟動時自動加載預設的內存監控動態鏈接庫(DLL,Dynamic Link Library),從而hook(掛鉤)內存分配函數和/或windows系統API(Application Programming Interface,應用程序編程接口)。

掛鉤模塊1104用于通過該內存監控動態鏈接庫掛鉤內存分配函數或windows系統應用程序編程接口。

具體地,在內存監控動態鏈接庫中利用微軟提供的detours庫來實現hook(掛鉤)C/C++標準庫中的內存分配函數(malloc、free和realloc等)的功能。或者,hook windows系統應用程序編程接口,即hook更底層的HeapAlloc系列函數(包括HeapAlloc、HeapFree和HeapRealloc)或hook底層的系統函數(RtAllocateHeap等)。HeapAlloc函數用來在指定的堆上分配內存,并且分配后的內存不可移動。采用hook C/C++標準庫中的內存分配函數,能大量去掉windows系統函數的影響,提高結果的精確性。

此外,還可同時在hook內存分配函數和windows系統應用程序編程接口之間切換。

收集模塊1106用于通過掛鉤函數調用該內存分配函數或windows系統應用程序編程接口,收集被測進程啟動時的內存分配信息,以及收集被測進程退出時的內存分配信息。

具體地,內存監控動態鏈接庫主要監控內存中malloc操作、free操作,包括內存分配的大小、內存分配的地址、內存釋放的地址、內存分配的函數堆棧等。hook函數調用內存分配函數malloc或free,通過記錄malloc操作和free操作,從而收集被測進程啟動時的內存分配信息。該內存分配信息可包括內存分 配地址、內存分配大小和內存分配的函數堆棧,或者包括內存分配大小和內存分配的函數堆棧,或者包括內存分配地址和內存分配大小。

比較模塊1108用于對該被測進程啟動時的內存分配信息及退出時的內存分配信息進行比較得出內存泄漏信息。

具體地,該內存分配信息可包括內存分配地址、內存分配大小和內存分配的函數堆棧,或者包括內存分配大小和內存分配的函數堆棧,或者包括內存分配地址和內存分配大小。

在一個實施例中,比較模塊1108可將被測進程啟動時內存分配信息中的內存分配地址和退出時的內存分配信息中的內存分配地址進行比較,判斷被測進程退出時內存分配信息中比被測進程啟動時內存分配信息中多的內存地址,則多的內存地址為內存泄漏地址,再得出內存泄漏大小。

在另一個實施例中,比較模塊1108可將被測進程啟動時內存分配信息的函數堆棧和退出時的內存分配信息中的函數堆棧進行比較,判斷被測進程退出時內存分配信息中比被測進程啟動時內存分配信息中多的函數堆棧,多的函數堆棧為函數堆棧內存泄漏。

圖12為另一個實施例中內存泄露檢測裝置的結構框圖。如圖12所示,一種內存泄漏檢測裝置,除了包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108,還包括第一統計模塊1110。其中:

第一統計模塊1110用于對多的函數堆棧按照對應的函數地址大小進行排序,再對排序后的函數堆棧進行分類統計,得出函數堆棧內存泄漏次數和函數內存泄漏大小。

具體地,將函數堆棧進行分類,統計同一類的函數堆棧的泄漏次數,并計算出所有函數堆棧內存泄漏大小。

采用函數堆棧比較實際是一組數的比較,只有組內每一個數都相等才算相同的函數堆棧,判斷兩個函數堆棧是否相等需要每個數都比較,大量堆棧查找的時候比較耗時,采用給函數堆棧排序,可將函數堆棧按照函數地址從大到小排序,或從小到大排序。排序處理后的函數堆棧通過使用std::set數據結構實現紅黑樹管理,使查找時間復雜度降為O(lgn),極大地縮短了查找時間。

此外,還可統計出內存泄漏的代碼行、嚴重程度、內存分配的函數堆棧的變化趨勢等,通過函數堆棧的變化趨勢更好的定位內存泄漏問題。

上述內存泄漏檢測裝置,通過在被測進程啟動時加載內存監控動態鏈接庫,通過內存監控動態鏈接庫掛鉤內存分配函數,收集被測進程啟動時的內存分配信息和退出后的內存分配信息,通過比較被測進程啟動時和退出時內存分配信息,得出內存泄漏信息,監控了被測進程從啟動開始到退出的整個過程中的內存分配信息,監控的時間點精確,得到的數據全面,且統計出來的結果是始終沒有釋放的,則得出的內存泄漏信息更加準確。

在一個實施例中,收集模塊1106還用于通過掛鉤函數調用該內存分配函數和/或windows系統應用程序編程接口,收集被測進程啟動后的內存監控信息。

圖13為另一個實施例中內存泄露檢測裝置的結構框圖。如圖13所示,一種內存泄漏檢測裝置,除了包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108,還包括傳輸模塊1112、讀取模塊1114、存儲模塊1116、取出模塊1118、分配模塊1120、刷新模塊1122、查找模塊1124、刪除模塊1126。

其中:傳輸模塊1112用于將該內存監控信息發送給數據處理進程,由該數據處理進程對該內存監控信息進行處理。

傳輸模塊1112還用于將該內存監控信息寫入共享內存中。

讀取模塊1114用于通過該數據處理進程的監控線程讀取該共享內存中的內存監控信息。

存儲模塊1116用于將讀取的內存監控信息存入該數據處理進程的緩存中。

取出模塊1118用于通過該數據處理進程的分配線程從該緩存中取出內存監控信息。

分配模塊1120用于分配給該數據處理進程的處理線程進行處理。

刷新模塊1122用于通過該數據處理進程的刷新線程對該被測進程的內存監控信息處理得到的內存分配信息進行刷新。

該內存監控信息為內存分配信息或內存釋放信息;

查找模塊1124用于當該內存監控信息為內存釋放信息時,根據該內存釋放 信息從該數據處理進程的高速緩存中查找是否存在對應的內存分配信息。

刪除模塊1126用于若該數據處理進程的高速緩存中存在對應的內存分配信息,則刪除該內存釋放信息及對應的內存分配信息。

以游戲程序中,玩家從一個場景進入另一個場景,在另一個場景結束后重返原來的場景,其內存泄漏檢測包括:

收集模塊1106還用于在進入一次被測場景后退出到前序場景開始收集第一內存快照,該第一內存快照記錄當前時刻的內存分配信息,以及在再次進入到被測場景后退出到前序場景開始收集第二內存快照,該第二內存快照記錄當前時刻的內存分配信息;

比較模塊1108還用于將第一內存快照記錄的內存分配信息及第二內存快照記錄的內存分配信息進行比較,得出被測場景的內存泄漏信息。

或者,收集模塊1106還用于在游戲程序啟動時收集第一內存快照,該第一內存快照記錄當前時刻的內存分配信息,以及在游戲程序退出時收集第二內存快照,該第二內存快照記錄當前時刻的內存分配信息;

比較模塊1108還用于將第一內存快照記錄的內存分配信息及第二內存快照記錄的內存分配信息進行比較,得出被測場景的內存泄漏信息。

該內存分配信息包括內存分配未釋放的地址、內存分配未釋放的大小和內存分配未釋放的函數堆棧;

比較模塊1108還用于將該第一內存快照記錄的內存分配信息中的函數堆棧和第二內存快照記錄的內存分配信息中的函數堆棧進行比較,判斷第二內存快照記錄的內存分配信息中比第一內存快照記錄的內存分配信息中多的函數堆棧,則多的函數堆棧為函數堆棧內存泄漏。

圖14為另一個實施例中內存泄露檢測裝置的結構框圖。如圖14所示,一種內存泄漏檢測裝置,除了包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108,還包括第二統計模塊1128。

第二統計模塊1128用于對多的函數堆棧按照對應的函數地址大小進行排序,再對排序后的函數堆棧進行分類統計,得出函數堆棧內存泄漏次數和函數內存泄漏大小。

具體地,將函數堆棧進行分類,統計同一類的函數堆棧的泄漏次數,并計算出所有函數堆棧內存泄漏大小。

在其他實施例中,內存泄露裝置可包括加載模塊1102、掛鉤模塊1104、收集模塊1106、比較模塊1108、第一統計模塊1110、傳輸模塊1112、讀取模塊1114、存儲模塊1116、取出模塊1118、分配模塊1120、刷新模塊1122、查找模塊1124、刪除模塊1126、第二統計模塊1128任意可能的組合。

本領域普通技術人員可以理解實現上述實施例方法中的全部或部分流程,是可以通過計算機程序來指令相關的硬件來完成,所述的程序可存儲于一非易失性計算機可讀取存儲介質中,該程序在執行時,可包括如上述各方法的實施例的流程。其中,所述的存儲介質可為磁碟、光盤、只讀存儲記憶體(Read-Only Memory,ROM)等。

以上所述實施例僅表達了本發明的幾種實施方式,其描述較為具體和詳細,但并不能因此而理解為對本發明專利范圍的限制。應當指出的是,對于本領域的普通技術人員來說,在不脫離本發明構思的前提下,還可以做出若干變形和改進,這些都屬于本發明的保護范圍。因此,本發明專利的保護范圍應以所附權利要求為準。

當前第1頁1 2 3 
網友詢問留言 已有0條留言
  • 還沒有人留言評論。精彩留言會獲得點贊!
1
韩国伦理电影