本申請涉及計算機技術(shù)領(lǐng)域,具體涉及一種監(jiān)控應(yīng)用程序內(nèi)存的方法以及一種監(jiān)控應(yīng)用程序內(nèi)存的裝置;本申請同時涉及一種電子設(shè)備。
背景技術(shù):
隨著現(xiàn)代系統(tǒng)規(guī)模日益擴大,系統(tǒng)中運行的應(yīng)用程序數(shù)量顯著增加。這些應(yīng)用程序通常都會消耗一定量的資源,比如內(nèi)存。其中某些應(yīng)用程序有可能會造成內(nèi)存泄漏、對象doublefree以及訪問地址越界等,在計算機科學中,內(nèi)存泄露是指由于疏忽或錯誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。內(nèi)存泄露并非指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,由于設(shè)計錯誤,失去了對該段內(nèi)存的控制,因而造成了內(nèi)存的浪費;doublefree其實就是同一個指針釋放兩次,雖然一般把它叫做doublefree,其實只要是多次釋放一個指向堆內(nèi)存的指針都有可能產(chǎn)生漏洞;訪問地址越界是向系統(tǒng)申請了一塊內(nèi)存,在使用這塊內(nèi)存的時候,超出了申請的范圍。造成的直接后果是修改了其它內(nèi)存塊的內(nèi)容,如果被修改的地址是正在使用中內(nèi)存,會造成應(yīng)用程序異常。
在應(yīng)用程序開發(fā)的過程中,由于往往需要隨著業(yè)務(wù)流或控制流的處理而進行大量的內(nèi)存申請和釋放,很容易造成在一些異常分支中遺漏釋放而出現(xiàn)內(nèi)存泄露的情形,然而這種內(nèi)存泄露的事件一般都是少量、且隱蔽的,需要經(jīng)過很長時間的積累甚至已經(jīng)造成了嚴重后果才能被察覺,難以檢測和恢復泄露的內(nèi)存。
目前,雖然已經(jīng)有一些輔助工具可以協(xié)助進行內(nèi)存泄漏、對象doublefree以及訪問地址越界的檢測。在現(xiàn)有技術(shù)下檢測內(nèi)存的常用工具包括:valgrind、glibc的mtrace/muntrace功能以及tcmalloc。其中,valgrind的執(zhí)行不需要重新編譯,而是和應(yīng)用程序在同一個進程中,動態(tài)的修改即將執(zhí)行的代碼,但正是因為valgrind的工作方式,導致程序性能驟降,根據(jù)注入代碼量的不同,性能會下降10-50倍,因為其對性能的影響,降低了其在復雜系統(tǒng)中的可用性;glibc的mtrace/muntrace功能利用malloc_hook機制,需要在記錄完成后重置malloc_hook函數(shù),所以其只能工作在單進程程序中,對于多進程程序因為 malloc_hook函數(shù)更改混亂會造成誤報或漏報,所以對于復雜的大型應(yīng)用程序可用性不高;tcmalloc可以檢查程序中是否有內(nèi)存泄露及內(nèi)存泄露點信息以及內(nèi)存性能及空間熱點分析,幫助分析內(nèi)存的使用分布情況。但需要調(diào)用backtrace函數(shù)獲取調(diào)用棧信息,而這個操作是一個慢操作,所以tcmalloc使用采樣的方式降低對應(yīng)用程序性能的影響,而采樣就可能存在偏差,從而影響結(jié)果的可靠性。
由此可見,在現(xiàn)有的監(jiān)控內(nèi)存的方案下,由于誤報、漏報或者由于其插樁的實現(xiàn)方法或算法復雜性因素引起程序運行緩慢降低性能的問題,從而影響結(jié)果的可靠性,對于復雜的大型應(yīng)用程序可用性不高,并且使用成本較高。
技術(shù)實現(xiàn)要素:
本申請?zhí)峁┮环N監(jiān)控應(yīng)用程序內(nèi)存的方法以及一種監(jiān)控應(yīng)用程序內(nèi)存的裝置,以解決現(xiàn)有技術(shù)中的上述問題。本申請同時涉及一種電子設(shè)備。
本申請?zhí)峁┝艘环N監(jiān)控應(yīng)用程序內(nèi)存的方法,所述監(jiān)控應(yīng)用程序內(nèi)存的方法包括:
應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間;
對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息;
對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息。
可選的,在所述應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間的步驟之前,包括:
將預(yù)設(shè)的重載函數(shù)庫鏈接到應(yīng)用程序中。
可選的,所述預(yù)設(shè)的重載函數(shù)庫,至少包括如下內(nèi)存管理函數(shù):
內(nèi)存分配函數(shù)、內(nèi)存釋放函數(shù)以及內(nèi)存調(diào)整函數(shù)。
可選的,所述將預(yù)設(shè)的重載函數(shù)庫鏈接到應(yīng)用程序中,包括:
若所述應(yīng)用程序是采用靜態(tài)鏈接的應(yīng)用程序,則在編譯時將靜態(tài)鏈接庫鏈接進應(yīng)用程序;
若所述應(yīng)用程序是采用動態(tài)連接的應(yīng)用程序,則在編譯時將動態(tài)鏈接庫鏈接進應(yīng)用程序或者應(yīng)用程序運行時,通過注入的方式把動態(tài)鏈接庫注入應(yīng)用程序。
可選的,所述應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,包括:
應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)申請內(nèi)存運行空間時,所述內(nèi)存管理函數(shù)在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間。
可選的,所述額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間是:用于記錄內(nèi)存信息的大小為16字節(jié)的標簽。
可選的,所述標簽記錄的信息,至少包括:
內(nèi)存塊狀態(tài)、內(nèi)存分配棧標識、時間戳、線程標識、桶標識以及標簽標識。
可選的,所述對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息,包括:
應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)分配申請的內(nèi)存運行空間時,判斷所述內(nèi)存管理函數(shù)是否成功分配申請的內(nèi)存運行空間;
若是,則在所述標簽中記錄本次內(nèi)存分配信息。
可選的,所述在所述標簽中記錄本次內(nèi)存分配信息,包括:
將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài);
調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識;
獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間;
獲取對申請的內(nèi)存運行空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對申請的內(nèi)存運行空間進行請求的線程標識;
根據(jù)申請的內(nèi)存運行空間的大小,將所述內(nèi)存運行空間進行分桶操作,并按照分桶操作的順序?qū)γ總€桶設(shè)置桶標識,在所述標簽中的桶標識中記錄當前內(nèi)存大小對應(yīng)桶的桶標識;
將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
可選的,所述對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息,包括:
應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)釋放申請的內(nèi)存運行空間時,在所述標簽中記錄本次內(nèi)存釋放信息。
可選的,所述在所述標簽中記錄本次內(nèi)存釋放信息,包括:
將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已釋放狀態(tài);
調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的內(nèi)存塊的釋放函數(shù)調(diào)用棧的標識;
獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間;
獲取對釋放的內(nèi)存空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對釋放的內(nèi)存空間進行請求的線程標識;
將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
可選的,所述調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,包括:
采用編譯器開關(guān)記錄回溯函數(shù)獲取函數(shù)調(diào)用棧的標識。
可選的,所述采用編譯器開關(guān)記錄回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,包括:
在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù);
通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識。
可選的,在所述標簽中記錄本次內(nèi)存釋放信息的步驟之前,包括:
判斷所述標簽中的內(nèi)存塊狀態(tài)是否為已分配狀態(tài);
若是,則執(zhí)行所述在所述標簽中記錄本次內(nèi)存釋放信息的步驟;
若否,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息。
可選的,在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)的步驟之前,還包括:
在所述跟蹤函數(shù)中預(yù)設(shè)內(nèi)存寫壞的判斷條件;
在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)的步驟之后,包括:
判斷內(nèi)存塊是否滿足預(yù)設(shè)內(nèi)存寫壞的判斷條件;
若是,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息;
若否,則執(zhí)行所述通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,并通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識的步驟。
可選的,在所述對申請的內(nèi)存運行空間進行分配或釋放時,還包括:
根據(jù)在應(yīng)用程序中已經(jīng)運行的進程的內(nèi)存鏡像信息,創(chuàng)建與該進程內(nèi)存鏡像相同的子進程。
可選的,當應(yīng)用程序發(fā)生異常時,獲取當前應(yīng)用程序的內(nèi)存布局,可以采用如下方式實現(xiàn):
調(diào)用終止函數(shù)使子進程終止運行,并轉(zhuǎn)存進程信息獲取應(yīng)用程序的內(nèi)存布局。
相應(yīng)的,本申請還提供了一種監(jiān)控應(yīng)用程序內(nèi)存的裝置,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置包括:
監(jiān)控空間請求單元,用于應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間;
內(nèi)存分配信息記錄單元,用于對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息;
內(nèi)存釋放信息記錄單元,用于對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:
重載函數(shù)庫鏈接單元,用于在所述應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間之前,將預(yù)設(shè)的重載函數(shù)庫鏈接到應(yīng)用程序中。
可選的,所述重載函數(shù)庫鏈接單元,鏈接到應(yīng)用程序中的至少包括如下內(nèi)存管理函數(shù):內(nèi)存分配函數(shù)、內(nèi)存釋放函數(shù)以及內(nèi)存調(diào)整函數(shù)。
可選的,所述重載函數(shù)庫鏈接單元,包括:
靜態(tài)鏈接子單元,用于若所述應(yīng)用程序是采用靜態(tài)鏈接的應(yīng)用程序,則在編譯時將靜態(tài)鏈接庫鏈接進應(yīng)用程序;
動態(tài)鏈接子單元,用于若所述應(yīng)用程序是采用動態(tài)連接的應(yīng)用程序,則在編譯時將動態(tài)鏈接庫鏈接進應(yīng)用程序或者應(yīng)用程序運行時,通過注入的方式把動態(tài)鏈接庫注入應(yīng)用程序。
可選的,所述監(jiān)控空間請求單元,具體用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)申請內(nèi)存運行空間時,所述內(nèi)存管理函數(shù)在內(nèi)存中額外 請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間。
可選的,所述監(jiān)控空間請求單元,具體用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)申請內(nèi)存運行空間時,所述內(nèi)存管理函數(shù)在內(nèi)存中額外請求用于記錄內(nèi)存信息的大小為16字節(jié)的標簽。
可選的,所述內(nèi)存分配信息記錄單元,包括:
判斷子單元,用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)分配申請的內(nèi)存運行空間時,判斷所述內(nèi)存管理函數(shù)是否成功分配申請的內(nèi)存運行空間;
內(nèi)存分配信息記錄子單元,用于接收所述判斷子單元的判斷結(jié)果,若是,則在所述標簽中記錄本次內(nèi)存分配信息。
可選的,所述內(nèi)存分配信息記錄子單元,包括:
已分配狀態(tài)設(shè)置子單元,用于將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài);
調(diào)用棧標識設(shè)置子單元,用于調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識;
時間設(shè)置子單元,用于獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間;
線程標識設(shè)置子單元,用于獲取對申請的內(nèi)存運行空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對申請的內(nèi)存運行空間進行請求的線程標識;
桶標識設(shè)置子單元,用于根據(jù)申請的內(nèi)存運行空間的大小,將所述內(nèi)存運行空間進行分桶操作,并按照分桶操作的順序?qū)γ總€桶設(shè)置桶標識,在所述標簽中的桶標識中記錄當前內(nèi)存大小對應(yīng)桶的桶標識;
標簽標識設(shè)置子單元,用于將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
可選的,所述內(nèi)存釋放信息記錄單元,具體用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)釋放申請的內(nèi)存運行空間時,在所述標簽中記錄本次內(nèi)存釋放信息。
可選的,所述內(nèi)存釋放信息記錄單元,包括:
已釋放狀態(tài)設(shè)置子單元,用于將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已釋放狀態(tài);
調(diào)用棧標識設(shè)置子單元,用于調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的內(nèi)存塊的釋放函數(shù)調(diào)用棧的標識;
釋放時間設(shè)置子單元,用于獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間;
線程標識更新子單元,用于獲取對釋放的內(nèi)存空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對釋放的內(nèi)存空間進行請求的線程標識;
標簽標識添加子單元,用于將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
可選的,所述調(diào)用棧標識設(shè)置子單元,具體用于采用編譯器開關(guān)記錄回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識。
可選的,所述調(diào)用棧標識設(shè)置子單元,包括:
跟蹤函數(shù)調(diào)用子單元,用于在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù);
標識獲取子單元,用于通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:
狀態(tài)判斷單元,用于在所述在所述標簽中記錄本次內(nèi)存釋放信息之前,判斷所述標簽中的內(nèi)存塊狀態(tài)是否為已分配狀態(tài);
內(nèi)存釋放信息記錄觸發(fā)單元,用于接收所述狀態(tài)判斷單元的判斷結(jié)果,若是,則執(zhí)觸發(fā)所述內(nèi)存釋放信息記錄單元;
終止函數(shù)調(diào)用單元,用于接收所述狀態(tài)判斷單元的判斷結(jié)果,若否,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:
條件設(shè)置單元,用于在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)之前,在所述跟蹤函數(shù)中預(yù)設(shè)內(nèi)存寫壞的判斷條件;
條件判斷單元,用于在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)之后,判斷內(nèi)存塊是否滿足預(yù)設(shè)內(nèi)存寫壞的判斷條件;
終止函數(shù)調(diào)用單元,用于接收所述條件判斷單元的判斷結(jié)果,若是,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息;
標識接收觸發(fā)單元,用于接收所述條件判斷單元的判斷結(jié)果,若否,則觸發(fā)所述標識獲取子單元。
可選的,所述內(nèi)存分配信息記錄單元,還包括:
子進程創(chuàng)建子單元,用于在所述對申請的內(nèi)存運行空間進行分配或釋放時,根據(jù)在應(yīng)用程序中已經(jīng)運行的進程的內(nèi)存鏡像信息,創(chuàng)建與該進程內(nèi)存鏡像相同的子進程。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:
內(nèi)存信息獲取單元,用于當應(yīng)用程序發(fā)生異常時,調(diào)用終止函數(shù)使子進程終止運行,并轉(zhuǎn)存進程信息獲取應(yīng)用程序的內(nèi)存布局。
此外,本申請還提供了一種電子設(shè)備,包括:
顯示器;
處理器;
存儲器,用于存儲內(nèi)存監(jiān)控程序,所述程序在被所述處理器讀取執(zhí)行時,執(zhí)行如下操作:應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間;對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息;對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息。
與現(xiàn)有技術(shù)相比,本申請具有以下優(yōu)點:
本申請?zhí)峁┑囊环N監(jiān)控應(yīng)用程序內(nèi)存的方法、裝置以及一種電子設(shè)備,通過申請內(nèi)存空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存空間;對申請的內(nèi)存空間進行分配時,在額外請求的內(nèi)存空間中記錄本次內(nèi)存分配信息;對申請的內(nèi)存空間進行釋放時,在額外請求的內(nèi)存空間中記錄本次內(nèi)存釋放信息。所述技術(shù)方案解決了由于誤報、漏報或者由于其插樁的實現(xiàn)方法或算法復雜性因素引起程序運行緩慢降低性能的問題,從而提高了結(jié)果的可靠性,解決了c/c++程序內(nèi)存使用中遇到的多種問題,對于復雜的大型應(yīng)用程序可用性高,并且使用成本較低。
附圖說明
為了更清楚地說明本申請實施例或現(xiàn)有技術(shù)中的技術(shù)方案,下面將對實施例或現(xiàn)有技術(shù)描述中所需要使用的附圖作簡單地介紹,顯而易見地,下面描述中的附圖僅僅是本申請中記載的一些實施例,對于本領(lǐng)域普通技術(shù)人員來講,還可以根據(jù)這些附圖獲得其他的附圖。
圖1示出了根據(jù)本申請的實施例提供的監(jiān)控應(yīng)用程序內(nèi)存的方法的流程圖;
圖2示出了根據(jù)本申請的實施例提供的對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息的方法的流程圖;
圖3示出了根據(jù)本申請的實施例提供的在所述標簽中記錄本次內(nèi)存分配信息的方法的流程圖;
圖4示出了根據(jù)本申請的實施例提供的采用編譯器將回溯函數(shù)注入應(yīng)用程序獲取函數(shù)調(diào)用棧的標識的方法的流程圖;
圖5示出了根據(jù)本申請的實施例提供的在所述標簽中記錄本次內(nèi)存釋放信息的方法的流程圖;
圖6示出了根據(jù)本申請的實施例提供的監(jiān)控應(yīng)用程序內(nèi)存的裝置的示意圖;
圖7示出了根據(jù)本申請的實施例提供的電子設(shè)備的示意圖。
具體實施方式
為了能夠更清楚地理解本申請的上述目的、特征和優(yōu)點,下面結(jié)合附圖和具體實施方式對本申請進行進一步的詳細描述。需要說明的是,在不沖突的情況下,本申請的實施例及實施例中的特征可以相互組合。
在下面的描述中闡述了很多具體細節(jié)以便于充分理解本申請。但是,本申請能夠以很多不同于在此描述的其它方式來實施,本領(lǐng)域技術(shù)人員可以在不違背本申請內(nèi)涵的情況下做類似推廣,因此,本申請不受下面公開的具體實施的限制。
本申請的實施例提供了一種監(jiān)控應(yīng)用程序內(nèi)存的方法以及一種監(jiān)控應(yīng)用程序內(nèi)存的裝置,本申請的實施例同時提供了一種電子設(shè)備。在下面的實施例中逐一進行詳細說明。
目前,雖然已經(jīng)有一些輔助工具可以協(xié)助進行內(nèi)存泄漏、對象doublefree以及訪問地址越界的檢測。在現(xiàn)有技術(shù)下檢測內(nèi)存的常用工具包括:valgrind、glibc的mtrace/muntrace功能以及tcmalloc。其中,valgrind的執(zhí)行不需要重新編譯,而是和應(yīng)用程序在同一個進程中,動態(tài)的修改即將執(zhí)行的代碼,但正是因為valgrind的工作方式,導致程序性能驟降,根據(jù)注入代碼量的不同,性能會下降10-50倍,因為其對性能的影響,降低了其在復雜系統(tǒng)中的可用性;glibc的mtrace/muntrace功能利用malloc_hook機制,需要在記錄完成后重置malloc_hook函數(shù),所以其只能工作在單進程程序中,對于多進程程序因為malloc_hook函數(shù)更改混亂會造成誤報或漏報,所以對于復雜的大型應(yīng)用程序可用性不高;tcmalloc可以檢查程序中是否有內(nèi)存泄露及內(nèi)存泄露點信息以及內(nèi)存性能及空間熱點分析,幫助分析內(nèi)存的使用分布情況。但需要調(diào)用backtrace函數(shù)獲取調(diào)用棧信息,而這個操作是一個慢操作,所以tcmalloc使用采樣的方式降低對應(yīng)用程序性能的影響,而采樣就可能存在偏差,從而影響結(jié)果的可靠性。由此可見,在現(xiàn)有的監(jiān)控內(nèi)存的方案下,由于誤報、漏報或者由于其插樁的實現(xiàn)方法或算法復雜性因素引起程序運行緩慢降低性能的問題,從而影響結(jié)果的可靠性,對于復雜的大型應(yīng)用程序可用性不高,并且使用成本較高。針對這一問題,本申請的技術(shù)方案通過應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,并在內(nèi)存監(jiān)控空間中記錄內(nèi)存分配信息以及內(nèi)存釋放信息,從而實現(xiàn)了監(jiān)控內(nèi)存的功能。
本申請的實施例提供了一種監(jiān)控應(yīng)用程序內(nèi)存的方法,一般性的,本實施例所述的監(jiān)控應(yīng)用程序內(nèi)存的方法由內(nèi)存監(jiān)控程序完成,該方法通過應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,并在內(nèi)存監(jiān)控空間中記錄內(nèi)存分配信息以及內(nèi)存釋放信息,完成對內(nèi)存的監(jiān)控。所述監(jiān)控應(yīng)用程序內(nèi)存的方法實施例如下:
請參考圖1,其示出了根據(jù)本申請的實施例提供的監(jiān)控應(yīng)用程序內(nèi)存的方法的流程圖。
所述監(jiān)控應(yīng)用程序內(nèi)存的方法包括:
步驟s101,應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間。
一個應(yīng)用程序在開始運行之后,會根據(jù)需求的內(nèi)存運行空間的大小向操作系統(tǒng)申請內(nèi)存空間,但是,在本實施例中,所述應(yīng)用程序除了向操作系統(tǒng)申請內(nèi)存運行空間外,還會向操作系統(tǒng)申請內(nèi)存監(jiān)控空間,所述應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,可以采用如下方式實現(xiàn):應(yīng)用程序在開始運行之后,所述應(yīng)用程序會根據(jù)需求的內(nèi)存運行空間的大小和預(yù)設(shè)大小的內(nèi)存監(jiān)控空間向操作系統(tǒng)申請內(nèi)存空間,該內(nèi)存空間的大小是所述應(yīng)用程序需求的內(nèi)存運行空間和內(nèi)存監(jiān)控空間的大小的總和。
例如:預(yù)設(shè)內(nèi)存監(jiān)控空間的大小占用n個字節(jié),則應(yīng)用程序在每次申請內(nèi)存運行空間時,實際申請內(nèi)存的空間可以比應(yīng)用程序所需的內(nèi)存運行空間多n個字節(jié),該n個字節(jié)的內(nèi)存監(jiān)控空間可以用于存放記錄該應(yīng)用程序的內(nèi)存分配信息以及內(nèi)存釋放信息。
需要說明的是,所述應(yīng)用程序申請內(nèi)存運行空間是該應(yīng)用程序在運行時需要使用的內(nèi)存空間,所述內(nèi)存運行空間可以預(yù)先根據(jù)具體的應(yīng)用場景設(shè)定的閾值來確定的,在應(yīng)用程序的初始化過程中,就可以將該閾值傳遞進來,并按照該閾值向操作系統(tǒng)進行申請內(nèi)存空間;所述內(nèi)存監(jiān)控空間用于記錄該應(yīng)用程序的內(nèi)存分配信息以及內(nèi)存釋放信息。
由于所述內(nèi)存監(jiān)控空間是通過預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)進行申請以及記錄該應(yīng)用程序的內(nèi)存分配信息以及內(nèi)存釋放信息的,所以在所述應(yīng)用程序在向操作系統(tǒng)進行申請預(yù)設(shè)大小的內(nèi)存監(jiān)控空間之前,需要將預(yù)設(shè)的內(nèi)存管理函數(shù)鏈接進所述應(yīng)用程序中。
在本實施例中,在執(zhí)行步驟s101應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間的步驟之前,將預(yù)設(shè)的重載函數(shù)庫鏈接到應(yīng)用程序中。
需要說明的是,c語言中有一些函數(shù)不需要進行編譯,有一些函數(shù)也可以在多個文件中使用。一般來說,可以事先對這些函數(shù)進行編譯,然后將它們放置在一些特殊的目標代碼文件中,這些目標代碼文件就稱為函數(shù)庫。函數(shù)庫文件中的函數(shù)可以通過連接程序與應(yīng)用程序進行連接。
函數(shù)庫可以有三種使用的形式:靜態(tài)、導入和動態(tài)。靜態(tài)鏈接庫的代碼在編 譯時就已連接到應(yīng)用程序中,函數(shù)和數(shù)據(jù)被編譯進一個二進制文件(通常windows下擴展名為.lib,linux/unix下擴展名為.a)。在使用靜態(tài)鏈接庫的情況下,在編譯鏈接可執(zhí)行文件時,鏈接器從函數(shù)庫中復制這些函數(shù)和數(shù)據(jù)并把它們和應(yīng)用程序的其它模塊組合起來創(chuàng)建最終的可執(zhí)行文件。而導入函數(shù)庫只是在程序開始運行時才載入,在編譯時,只是簡單地指定需要使用的庫函數(shù)。動態(tài)鏈接庫也是在程序運行時載入,但與導入函數(shù)庫不同的是,使用的庫函數(shù)不是在應(yīng)用程序運行開始,而是在應(yīng)用程序中的語句需要使用該函數(shù)時才載入在使用動態(tài)鏈接庫的時候。在編譯鏈接可執(zhí)行文件時,動態(tài)鏈接庫中的函數(shù)代碼和數(shù)據(jù)并不復制到可執(zhí)行文件中,在運行的時候,再去加載,訪問庫中導出的函數(shù)。動態(tài)鏈接庫可以在應(yīng)用程序運行期間釋放動態(tài)鏈接庫所占用的內(nèi)存,騰出空間供其它應(yīng)用程序使用。由于導入函數(shù)庫和動態(tài)鏈接庫并沒有在應(yīng)用程序中包括庫函數(shù)的內(nèi)容,只是包含了對庫函數(shù)的引用,因此代碼的規(guī)模比較小。
在本實施例中,提供一個動態(tài)鏈接版本及一個靜態(tài)鏈接版本的重載函數(shù)庫,所述將預(yù)設(shè)的重載函數(shù)庫鏈接到應(yīng)用程序中,可以采用如下方式實現(xiàn):若所述應(yīng)用程序是采用靜態(tài)鏈接的應(yīng)用程序,則在編譯時將靜態(tài)鏈接庫鏈接進應(yīng)用程序;若所述應(yīng)用程序是采用動態(tài)連接的應(yīng)用程序,則在編譯時將動態(tài)鏈接庫鏈接進應(yīng)用程序或者應(yīng)用程序運行時,通過注入的方式把動態(tài)鏈接庫注入應(yīng)用程序。
需要說明的是,在編譯時將靜態(tài)鏈接庫靜態(tài)鏈接進應(yīng)用程序的時候,載入代碼就會把應(yīng)用程序會用到的動態(tài)代碼或動態(tài)代碼的地址確定下來靜態(tài)鏈接庫的鏈接可以使用靜態(tài)鏈接,動態(tài)鏈接庫也可以使用這種方法鏈接導入庫;在應(yīng)用程序調(diào)用內(nèi)存管理函數(shù)時通過注入的方式把動態(tài)鏈接庫注入應(yīng)用程序使用的動態(tài)鏈接方法并不在一開始就完成動態(tài)鏈接,而是直到真正調(diào)用動態(tài)鏈接庫代碼時,載入程序才計算(被調(diào)用的那部分)動態(tài)代碼的邏輯地址,然后等到某個時候,應(yīng)用程序又需要調(diào)用另外某塊動態(tài)代碼時,載入程序又去計算這部分代碼的邏輯地址,所以,這種方式使程序初始化時間較短,但運行期間的性能比不上靜態(tài)鏈接的程序??梢岳斫獾模o態(tài)鏈接庫和應(yīng)用程序編譯在一起,在任何情況下都能運行,而動態(tài)鏈接庫是動態(tài)鏈接,顧名思義就是在應(yīng)用程序啟動的時候才會鏈接,所以,當操作系統(tǒng)上沒有該動態(tài)鏈接庫時,應(yīng)用程序就會運行失敗。
需要說明的是,所述預(yù)設(shè)的重載函數(shù)庫中重新實現(xiàn)了函數(shù)庫中的各種內(nèi)存管 理函數(shù),至少包括如下內(nèi)存管理函數(shù):內(nèi)存分配函數(shù)、內(nèi)存釋放函數(shù)以及內(nèi)存調(diào)整函數(shù),在本實施例中,所述預(yù)設(shè)的重載函數(shù)庫中重新實現(xiàn)了函數(shù)庫中的各種內(nèi)存管理函數(shù),可以采用如下方式實現(xiàn):對c語言函數(shù)庫最基本的內(nèi)存分配函數(shù)、內(nèi)存調(diào)整函數(shù)等作宏定義重載,即:用自定義的同名函數(shù)系列覆蓋標準c語言中的malloc等內(nèi)存管理函數(shù),增加申請以及記錄內(nèi)存監(jiān)控空間的相關(guān)代碼,用已封裝后的代碼替換原函數(shù),從而實現(xiàn)函數(shù)的宏定義重載,以下簡稱重載函數(shù),對重載后的函數(shù)庫稱為重載函數(shù)庫。通過重載函數(shù)策略,確保了重載前后應(yīng)用程序?qū)語言庫函數(shù)的接口調(diào)用的一致性,同時也實現(xiàn)了在應(yīng)用程序運行的過程中,重載函數(shù)庫中的新內(nèi)存管理函數(shù)申請內(nèi)存監(jiān)控空間和記錄內(nèi)存分配信息和內(nèi)存釋放信息的功能。
例如:在編碼實現(xiàn)中,可以通過將c語言函數(shù)庫提供的malloc、free、calloc以及realloc函數(shù)改造成宏函數(shù),使之后對函數(shù)進行調(diào)用時感受不到編碼上的差異。具體實施方式可以為:可以自定義new_malloc函數(shù)、new_calloc函數(shù)、new_realloc函數(shù)實現(xiàn)申請內(nèi)存監(jiān)控空間,可以自定義new_free函數(shù)實現(xiàn)釋放內(nèi)存監(jiān)控空間。
下面對所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)進行詳細說明。
c語言函數(shù)庫提供了內(nèi)存分配函數(shù)malloc、內(nèi)存釋放函數(shù)free、內(nèi)存調(diào)整函數(shù)realloc等基于內(nèi)存的管理函數(shù),負責分配可用內(nèi)存以及釋放用過的內(nèi)存。
其中,內(nèi)存分配函數(shù)malloc的作用是向操作系統(tǒng)申請分配指定若干個字節(jié)的內(nèi)存空間,并返回類型是void*類型,void*表示未確定類型的指針。malloc不能分配的時候返回null。malloc函數(shù)的實質(zhì)體現(xiàn)在,它有一個將可用的內(nèi)存塊連接為一個長長的列表,調(diào)用malloc函數(shù)時,它沿表尋找一個大到足以滿足用戶請求所需要的內(nèi)存塊。如果無法獲得符合要求的內(nèi)存塊,malloc函數(shù)會返回null指針。
內(nèi)存釋放函數(shù)free是釋放malloc(或calloc、realloc)函數(shù)給指針變量分配的內(nèi)存空間的函數(shù)。free函數(shù)與malloc函數(shù)配對使用,free函數(shù)獲得指向由malloc分配的內(nèi)存片段的指針,釋放malloc函數(shù)申請的動態(tài)內(nèi)存,以便以后的程序或操作系統(tǒng)使用。free函數(shù)清除指向的地址,它只作清除的工作,并告訴操作系統(tǒng)這塊地址已經(jīng)被釋放和清除,可以重新被分配。
內(nèi)存調(diào)整函數(shù)realloc以所指地址為首址,分配若干個字節(jié)的內(nèi)存,并返回 所指地址。realloc不會初始化分配到的內(nèi)存塊,如果所指地址為null則相當于malloc,如果分配的若干個字節(jié)的內(nèi)存為null則相當于free,如果重新分配成功則返回指向被分配內(nèi)存的指針,否則返回空指針null。在使用realloc函數(shù)時先判斷當前的指針是否有足夠的連續(xù)內(nèi)存空間,如果有則擴大指向的地址,如果內(nèi)存空間不夠,則按照指定的大小分配空間,將原有數(shù)據(jù)從頭到尾拷貝到新分配的內(nèi)存空間,而后釋放原來所指內(nèi)存區(qū)域,同時返回新分配的內(nèi)存空間的首地址。即重新分配存儲器塊的地址。
需要說明的是,所述預(yù)設(shè)的重載函數(shù)庫中除了內(nèi)存分配函數(shù)malloc、內(nèi)存釋放函數(shù)free、內(nèi)存調(diào)整函數(shù)realloc還包括:valloc、memalign以及posix_memalign函數(shù),由于在調(diào)用上述函數(shù)時都會在應(yīng)用程序運行的過程中申請內(nèi)存監(jiān)控空間和記錄內(nèi)存分配信息和內(nèi)存釋放信息,上述函數(shù)的具體功能在此不再贅述。
在本實施例中,所述應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,可以采用如下方式實現(xiàn):應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)申請內(nèi)存運行空間時,所述內(nèi)存管理函數(shù)在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間。所述額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間是:用于記錄內(nèi)存信息的大小為16字節(jié)的標簽。
需要說明的是,所述標簽的數(shù)據(jù)結(jié)構(gòu)具體如下:
其中,allocate_or_free_marker記錄的是該內(nèi)存塊狀態(tài),標識此內(nèi)存塊的狀態(tài)是否為使用中,例如:若該內(nèi)存塊狀態(tài)為allocate則說明該內(nèi)存塊處于已分配狀態(tài);若該內(nèi)存塊狀態(tài)為free則說明該內(nèi)存塊處于釋放狀態(tài)。
allocate_or_free_backtrace_id記錄的是當前函數(shù)調(diào)用棧的標識,通過分配函數(shù)調(diào)用棧的標識可以獲得內(nèi)存塊最后操作的函數(shù)地址,例如:分配函數(shù)調(diào)用棧的標識可以是分配函數(shù)調(diào)用棧的id。
allocate_or_free_timestamp記錄的是時間戳,例如:對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間以及對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間。
allocate_or_free_tid記錄的是對申請的內(nèi)存運行空間進行請求的線程標識以及對釋放的內(nèi)存空間進行請求的線程標識。
memory_bucket_id記錄的是重載函數(shù)庫中的內(nèi)存管理函數(shù)根據(jù)申請的內(nèi)存運行空間的大小,將所述內(nèi)存運行空間進行分桶操作的順序?qū)Ξ斍皟?nèi)存大小對應(yīng)桶設(shè)置的桶標識,記錄后通過memory_bucket_id可以獲取本內(nèi)存塊的空間信息。
memory_tracer_tag_marker記錄的是用于區(qū)分在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間的標識,可以理解的,由于該標簽是在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,所以通過該標簽標識可以在應(yīng)用程序內(nèi)存中標識以及區(qū)分該標簽的位置,便于讀取。
可以理解的,所述標簽中記錄的數(shù)據(jù)分別對應(yīng)于內(nèi)存分配信息和內(nèi)存釋放信息中的設(shè)置的內(nèi)存塊狀態(tài)、內(nèi)存分配棧標識、時間戳、線程標識、桶標識以及標簽標識。
為了能在不影響應(yīng)用程序運行的情況下獲取完整的內(nèi)存使用信息,本實施例的技術(shù)方案提供了一種優(yōu)選實施方式,在優(yōu)選方式下,所述對申請的內(nèi)存運行空間進行分配或釋放時,根據(jù)在應(yīng)用程序中已經(jīng)運行的進程的內(nèi)存鏡像信息,創(chuàng)建與該進程內(nèi)存鏡像相同的子進程。
需要說明的是,可以采用fork函數(shù)實現(xiàn),根據(jù)在應(yīng)用程序中已經(jīng)運行的進程的資源信息(內(nèi)存空間、堆、棧等資源),創(chuàng)建與該進程資源相同的子進程。fork函數(shù)是計算機程序設(shè)計中的分叉函數(shù),將運行著的應(yīng)用程序分成2個完全一樣的進程,每個進程都啟動一個從代碼的同一位置開始執(zhí)行的進程。這兩個進程中的進程繼續(xù)執(zhí)行,就像是兩個用戶同時啟動了該應(yīng)用程序的兩個副本,由fork創(chuàng)建的新進程被稱為子進程。fork函數(shù)被調(diào)用一次但返回兩次。兩次返回的唯一區(qū)別是子進程中返回0值而父進程中返回子進程id。
在所述根據(jù)在應(yīng)用程序中已經(jīng)運行的進程的內(nèi)存鏡像信息,創(chuàng)建與該進程內(nèi)存鏡像相同的子進程的步驟之后,根據(jù)與該進程內(nèi)存鏡像相同的子進程,獲取父進程在額外請求的內(nèi)存監(jiān)控空間中完整記錄的內(nèi)存分配信息及內(nèi)存釋放信息。
在本實施例中,所述當應(yīng)用程序發(fā)生異常時,獲取當前應(yīng)用程序的內(nèi)存布局,可以采用如下方式實現(xiàn):
調(diào)用終止函數(shù)使子進程終止運行,并轉(zhuǎn)存進程信息獲取應(yīng)用程序的內(nèi)存布局。
可以理解的,轉(zhuǎn)存進程信息獲取的應(yīng)用程序的內(nèi)存布局,實際就是父進程在額外請求的內(nèi)存監(jiān)控空間中記錄的完整內(nèi)存分配信息及內(nèi)存釋放信息。
需要說明的是,調(diào)用abort()函數(shù)使子進程終止運行,獲取該應(yīng)用程序的完整內(nèi)存鏡像,并在內(nèi)存鏡像中獲取在額外請求的內(nèi)存監(jiān)控空間中記錄的完整內(nèi)存分配信息及內(nèi)存釋放信息,從而獲得任何一個內(nèi)存地址的使用狀態(tài)及最后的屬主信息。
可以理解的,在子進程終止運行時,該應(yīng)用程序還可以在所在的父進程中正常運行。
步驟s103,對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息。
在本實施例中,所述對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息,可以采用如下方式實現(xiàn):應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)分配申請的內(nèi)存運行空間,并將本次內(nèi)存分配信息記錄在額外請求的內(nèi)存監(jiān)控空間中。所述額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間是:用于記錄內(nèi)存信息的大小為16字節(jié)的標簽。
為了使在額外請求的內(nèi)存監(jiān)控空間中記錄的本次內(nèi)存分配信息更加準確,本實施例的技術(shù)方案提供了一種優(yōu)選實施方式,在優(yōu)選方式下,所述對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息,具體包括步驟s103-1至s103-2,下面結(jié)合附圖2作進一步說明。
請參考圖2,其示出了根據(jù)本申請的實施例提供的對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息的方法的流程圖。
步驟s103-1,應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)分配申請的內(nèi)存運行空間時,判斷所述內(nèi)存管理函數(shù)是否成功分配申請的內(nèi)存運行空間。
在本實施例中,所述判斷所述內(nèi)存管理函數(shù)是否成功分配申請的內(nèi)存運行空間,可以采用如下方式實現(xiàn):判斷內(nèi)存分配函數(shù)malloc的返回值是否不為null,若是,則執(zhí)行步驟s103-2,若是,則在所述標簽中記錄本次內(nèi)存分配信息。
需要說明的是,內(nèi)存分配函數(shù)malloc的返回類型是void*類型。當malloc函數(shù)的返回值為null時表示內(nèi)存分配不成功,返回值不為null時表示分配正常,程序繼續(xù)向下運行。
步驟s103-2,若是,則在所述標簽中記錄本次內(nèi)存分配信息。
在本實施例中,若接收到內(nèi)存分配函數(shù)malloc的返回值不為null的判斷結(jié)果,則將本次內(nèi)存分配信息記錄在額外請求的內(nèi)存監(jiān)控空間中。
在本實施例中,所述在所述標簽中記錄本次內(nèi)存分配信息,具體包括步驟s103-2-1至s103-2-6,下面結(jié)合附圖3作進一步說明。
請參考圖3,其示出了根據(jù)本申請的實施例提供的在所述標簽中記錄本次內(nèi)存分配信息的方法的流程圖。
步驟s103-2-1,將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài)。
在本實施例中,所述將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài),可以采用如下方式實現(xiàn):當malloc函數(shù)的返回值不為null時,則將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài)。
例如:將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為allocate。
步驟s103-2-2,調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識。
需要說明的是,所述回溯函數(shù),例如:intbacktrace(void**buffer,intsize)用于獲取函數(shù)調(diào)用堆棧,將獲取的信息存放在buffer中,buffer是一個指針列表,參數(shù)size用來指定buffer中可以保存多少個void*元素。函數(shù)返回值是實際獲取的指針個數(shù),最大不超過size大小,在本實施例中,通過所述回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,并將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識。
需要說明的是,分配內(nèi)存塊的客戶或擁有者可以通過請求了內(nèi)存分配和/ 或釋放的應(yīng)用程序的可執(zhí)行代碼序列或者棧的回溯來表示。在復雜的應(yīng)用程序中,回溯對于更精確地識別應(yīng)用程序活動的特定子集是很有用的。全局分配表中的每一個條目記錄了內(nèi)存分配的一條回溯路徑,這些路徑使用散列值進行索引。隨后,在內(nèi)存分配/釋放過程中,更新相應(yīng)回溯路徑上分配/釋放的內(nèi)存大小。
由于backtrace操作性能較低,所以默認只會對特定的backtrace_id進行抽樣調(diào)用,若全部調(diào)用則將導致大型的應(yīng)用程序不能正常運行。為了解決backtrace性能問題,本實施例的技術(shù)方案提供了一種優(yōu)選實施方式,在優(yōu)選方式下,所述調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,可以采用編譯器開關(guān)記錄回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識,具體說,就是采用編譯器開關(guān)逐層記錄回溯函數(shù)所需內(nèi)容以替換backtrace操作。所述采用編譯器開關(guān)記錄回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識,具體包括步驟s103-2-2-1至s103-2-2-2,下面結(jié)合附圖4作進一步說明。
請參考圖4,其示出了根據(jù)本申請的實施例提供的采用編譯器將回溯函數(shù)注入應(yīng)用程序獲取函數(shù)調(diào)用棧的標識的方法的流程圖。
步驟s103-2-2-1,在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)。
在本實施例中,所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù),可以采用如下方式實現(xiàn):使用gcc(gnucompilercollection)添加-finstrument-functions編譯器在編譯的過程中插入相應(yīng)的代碼,-finstrument-functions使在每個函數(shù)調(diào)用之前調(diào)用一個名為__cyg_profile_func_enter的跟蹤函數(shù),在每個函數(shù)退出時調(diào)用一個名為__cyg_profile_func_exit的跟蹤函數(shù)。
例如:在函數(shù)調(diào)用的入口調(diào)用:void__cyg_profile_func_enter(void*func_address,void*call_site);在函數(shù)調(diào)用的出口調(diào)用:void__cyg_profile_func_exit(void*func_address,void*call_site)。
由于應(yīng)用程序bug造成申請的內(nèi)存不足或者野指針操作會造成應(yīng)用程序內(nèi)存被寫壞,而且內(nèi)存被寫壞后訪問這些內(nèi)存將導致應(yīng)用程序行為不可預(yù)期,且觸發(fā)時間和問題時間間隔可能較長,從而現(xiàn)場破壞,問題難于調(diào)查,為了解決內(nèi)存被寫壞的問題,本實施例的技術(shù)方案提供了一種優(yōu)選實施方式,在優(yōu)選方式下,在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)的步驟之前,在所述跟蹤函數(shù)中預(yù)設(shè)內(nèi)存寫壞的判斷條件。
例如:在跟蹤函數(shù)__cyg_profile_func_enter和__cyg_profile_func_exit中加入檢查點,即滿足內(nèi)存寫壞的判斷條件pattern。
與在所述跟蹤函數(shù)中預(yù)設(shè)內(nèi)存寫壞的判斷條件的步驟相對應(yīng)的,本實施例的技術(shù)方案提供了一種優(yōu)選實施方式,在優(yōu)選方式下步驟s103-2-2-1在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)之后,具體包括如下步驟:
判斷內(nèi)存塊是否滿足預(yù)設(shè)內(nèi)存寫壞的判斷條件;
若是,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息;
若否,則執(zhí)行所述通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,并通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識的步驟。
可以理解的,判斷內(nèi)存塊是否滿足預(yù)設(shè)內(nèi)存寫壞的判斷條件的步驟是在調(diào)用__cyg_profile_func_enter和__cyg_profile_func_exit函數(shù)之后,通過在上述函數(shù)中的檢查點判斷當前內(nèi)存塊是否被寫壞。
需要說明的是,所述終止函數(shù)是abort()函數(shù),該函數(shù)的作用是異常終止一個進程,具體的,abort()函數(shù)首先解除進程對sigabrt信號的阻止,然后向調(diào)用進程發(fā)送該信號。abort()函數(shù)會導致進程的異常終止除非sigabrt信號被捕捉并且信號處理句柄沒有返回。
步驟s103-2-2-2,通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識。
在本實施例中,所述通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識,可以采用如下方式實現(xiàn):在重載函數(shù)庫中定義線程局部變量,并接收在函數(shù)調(diào)用的入口調(diào)用的__cyg_profile_func_enter函數(shù)和在函數(shù)調(diào)用的出口調(diào)用的__cyg_profile_func_exit函數(shù)實時更新當前線程函數(shù)調(diào)用棧,并在線程局部變量中記錄,之后通過回溯函數(shù)匯總棧信息,并獲取和此分配函數(shù)調(diào)用棧匹配的標識。
需要說明的是,在所述通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識的步驟之后,將所述標簽中的內(nèi)存分配棧標識設(shè)置為記錄分配函數(shù)調(diào)用棧的標識。
步驟s103-2-3,獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間。
在本實施例中,所述獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,可以采用如下方式實現(xiàn):利用操作系統(tǒng)提供的接口獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,并將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間。
例如:例如,可以使用操作系統(tǒng)提供的gettimeofday函數(shù)實現(xiàn)上述獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間的功能。
步驟s103-2-4,獲取對申請的內(nèi)存運行空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對申請的內(nèi)存運行空間進行請求的線程標識。
在本實施例中,所述獲取對申請的內(nèi)存運行空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對申請的內(nèi)存運行空間進行請求的線程標識,可以采用如下方式實現(xiàn):當應(yīng)用程序的線程對申請的內(nèi)存運行空間進行請求時,會根據(jù)請求的內(nèi)存大小獲取符合預(yù)置條件的內(nèi)存空間,分配給該線程并獲取線程的標識,將所述標簽中的線程標識設(shè)置為獲取的對申請的內(nèi)存運行空間請求內(nèi)存的線程的標識。
例如:假設(shè)線程請求的內(nèi)存大小是1m,則操作系統(tǒng)會在內(nèi)存中選擇同樣為1m的內(nèi)存空間分配給該線程,此時,操作系統(tǒng)選擇的這1m的內(nèi)存空間被稱為一個內(nèi)存塊,當線程將這1m的內(nèi)存釋放之后,該內(nèi)存塊就成為空閑的內(nèi)存空間,即該內(nèi)存塊可以分配給其他的線程。
步驟s103-2-5,根據(jù)申請的內(nèi)存運行空間的大小,將所述內(nèi)存運行空間進行分桶操作,并按照分桶操作的順序?qū)γ總€桶設(shè)置桶標識,在所述標簽中的桶標識中記錄當前內(nèi)存大小對應(yīng)桶的桶標識。
需要說明的是,所述分桶操作相當于對申請的內(nèi)存運行空間進行預(yù)分配的過程,即在向操作系統(tǒng)申請到內(nèi)存運行空間之后,首先將其劃分為多個內(nèi)存塊,然后再將其劃分為多個內(nèi)存桶,也就是說,在程序進行具體的內(nèi)存請求之前已經(jīng)對申請到的內(nèi)存空間進行了劃分。當一個進程請求內(nèi)存空間時,會攜帶有需要的內(nèi)存空間大小的信息,根據(jù)請求的內(nèi)存空間大小,選擇符合預(yù)置條件的內(nèi)存桶。例如,可以選擇大于用戶請求的內(nèi)存大小的最小內(nèi)存桶;換言之,當某進程請求內(nèi)存時,意味著有數(shù)據(jù)需要存放在內(nèi)存中,因此,請求的內(nèi)存空間大小取決于需要存放的數(shù)據(jù)的大小。
在本實施例中,內(nèi)存桶是預(yù)先劃分好的,在進行內(nèi)存空間分配時也是按內(nèi)存桶進行分配,而進程請求的內(nèi)存空間大小是不確定的。
例如,申請的內(nèi)存運行空間的大小為10m,則將所述內(nèi)存運行空間進行分桶操作,將該內(nèi)存運行空間劃分為1m,2m,3m,4m4個內(nèi)存桶,并按照分桶操作的順序?qū)γ總€桶設(shè)置桶標識,即第一個1m的內(nèi)存桶的桶標識為1,第二個2m的內(nèi)存桶的桶標識為2,第三個3m的內(nèi)存桶的桶標識為3,第四個4m的內(nèi)存桶的桶標識為4,并在所述標簽中的桶標識中記錄每個桶的桶標識,通過桶標識就可以可以獲得本內(nèi)存分配塊的空間信息。
步驟s103-2-6,將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
需要說明的是,所述標簽標識是用于區(qū)分在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間的標識,可以理解的,由于該標簽是在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,所以通過該標簽標識可以在應(yīng)用程序內(nèi)存中標識以及區(qū)分該標簽的位置,便于讀取。例如:所述標簽中的標簽標識可以是“已添加標簽”或者是其他能區(qū)分內(nèi)存監(jiān)控空間和內(nèi)存運行空間的標識。
步驟s105,對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息。
在本實施例中,所述對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息,可以采用如下方式實現(xiàn):對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄該申請的內(nèi)存運行空間釋放后的內(nèi)存塊狀態(tài)、內(nèi)存分配棧標識、時間戳、線程標識、桶標識以及標簽標識。
在具體實施時,應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)釋放申請的內(nèi)存運行空間時,在所述標簽中記錄本次內(nèi)存釋放信息。所述額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間是:用于記錄內(nèi)存信息的大小為16字節(jié)的標簽。
在本實施例中,所述在所述標簽中記錄本次內(nèi)存釋放信息,具體包括步驟s105-1至s105-5,下面結(jié)合附圖5作進一步說明。
請參考圖5,其示出了根據(jù)本申請的實施例提供的在所述標簽中記錄本次內(nèi)存釋放信息的方法的流程圖。
步驟s105-1,將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已釋放狀態(tài)。
在本實施例中,所述將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已釋放狀態(tài),可以采 用如下方式實現(xiàn):free函數(shù)清除malloc(或calloc、realloc)函數(shù)給指針變量分配的內(nèi)存空間指向的地址后,則將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已釋放狀態(tài)。
例如:將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為free。
步驟s105-2,調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的內(nèi)存塊的釋放函數(shù)調(diào)用棧的標識。
需要說明的是,所述回溯函數(shù),例如:intbacktrace(void**buffer,intsize)用于獲取函數(shù)調(diào)用堆棧,將獲取的信息存放在buffer中,buffer是一個指針列表,參數(shù)size用來指定buffer中可以保存多少個void*元素。函數(shù)返回值是實際獲取的指針個數(shù),最大不超過size大小,在本實施例中,通過所述回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,并將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識。
由于backtrace操作性能較低,所以默認只會對特定的backtrace_id進行抽樣調(diào)用,若全部調(diào)用則將導致大型的應(yīng)用程序不能正常運行。為了解決backtrace性能問題,本實施例的技術(shù)方案提供了一種優(yōu)選實施方式,在優(yōu)選方式下,所述調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,可以采用編譯器將回溯函數(shù)注入應(yīng)用程序獲取函數(shù)調(diào)用棧的標識。所述采用編譯器將回溯函數(shù)注入應(yīng)用程序獲取函數(shù)調(diào)用棧的標識,由于在前面實施例中已經(jīng)對此進行了比較詳細的描述,此處不再贅述。
步驟s105-3,獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間。
在本實施例中,所述獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,可以采用如下方式實現(xiàn):利用操作系統(tǒng)提供的接口獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,并將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間。
例如,可以使用操作系統(tǒng)提供的gettimeofday函數(shù)實現(xiàn)上述獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間的功能。
步驟s105-4,獲取對釋放的內(nèi)存空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對釋放的內(nèi)存空間進行請求的線程標識。
在本實施例中,所述獲取對釋放的內(nèi)存空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對釋放的內(nèi)存空間進行請求的線程標識,可以采用如下方式實現(xiàn):當應(yīng)用程序的線程對釋放的內(nèi)存空間進行請求時,會獲取對釋放的內(nèi)存空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對釋放的內(nèi)存空間進行請求的線程標識。
步驟s105-5,將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
需要說明的是,所述標簽標識是用于區(qū)分在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間的標識,可以理解的,由于該標簽是在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間,所以通過該標簽標識可以在應(yīng)用程序內(nèi)存中標識以及區(qū)分該標簽的位置,便于讀取。例如:所述標簽中的標簽標識可以是“已添加標簽”或者是其他能區(qū)分內(nèi)存監(jiān)控空間和內(nèi)存運行空間的標識。
由于在對申請的內(nèi)存運行空間進行分配時,在所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài),用來表示內(nèi)存被使用的開始,所以在對申請的內(nèi)存運行空間進行釋放之前,需要對所述標簽中的內(nèi)存塊狀態(tài)進行識別,在所述標簽中記錄本次內(nèi)存釋放信息的步驟之前,具體包括如下步驟:
判斷所述標簽中的內(nèi)存塊狀態(tài)是否為已分配狀態(tài);
若是,則執(zhí)行所述在所述標簽中記錄本次內(nèi)存釋放信息的步驟;
若否,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息。
在本實施例中,如果在所述標簽中記錄本次內(nèi)存釋放信息之前,所述標簽中的內(nèi)存塊狀態(tài)為已釋放狀態(tài),則說明該內(nèi)存發(fā)生內(nèi)存重復釋放,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息,禁止釋放操作;如果在所述標簽中記錄本次內(nèi)存釋放信息之前,所述標簽中的內(nèi)存塊狀態(tài)為已分配狀態(tài),則說明該內(nèi)存為首次釋放,并執(zhí)行所述在所述標簽中記錄本次內(nèi)存釋放信息的步驟。
可以理解的,在釋放內(nèi)存時,可能為首次或重復釋放,為進行區(qū)分只需檢測所述標簽中的內(nèi)存塊狀態(tài),若所述標簽中的內(nèi)存塊狀態(tài)為已釋放狀態(tài),則說明該內(nèi)存發(fā)生內(nèi)存重復釋放;若所述標簽中的內(nèi)存塊狀態(tài)為已分配狀態(tài),則說明該內(nèi)存為首次釋放,可以進行釋放操作。
需要說明的是,所述終止函數(shù)是abort()函數(shù),該函數(shù)的作用是異常終止一個進程,具體的,abort()函數(shù)首先解除進程對sigabrt信號的阻止,然后向調(diào) 用進程發(fā)送該信號。abort()函數(shù)會導致進程的異常終止除非sigabrt信號被捕捉并且信號處理句柄沒有返回。
在上述的實施例中,提供了一種監(jiān)控應(yīng)用程序內(nèi)存的方法,與上述監(jiān)控應(yīng)用程序內(nèi)存的方法相對應(yīng)的,本申請還提供了一種監(jiān)控應(yīng)用程序內(nèi)存的裝置。由于裝置的實施例基本相似于方法的實施例,所以描述得比較簡單,相關(guān)之處參見方法實施例的部分說明即可。下述描述的裝置實施例僅僅是示意性的。所述監(jiān)控應(yīng)用程序內(nèi)存的裝置實施例如下:
請參考圖6,其示出了根據(jù)本申請的實施例提供的監(jiān)控應(yīng)用程序內(nèi)存的裝置的示意圖。
所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,包括:監(jiān)控空間請求單元601、內(nèi)存分配信息記錄單元603以及內(nèi)存釋放信息記錄單元605;
所述監(jiān)控空間請求單元601,用于應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間;
所述內(nèi)存分配信息記錄單元603,用于對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存分配信息;
所述內(nèi)存釋放信息記錄單元605,用于對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:重載函數(shù)庫鏈接單元;
所述重載函數(shù)庫鏈接單元,用于在所述應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間之前,將預(yù)設(shè)的重載函數(shù)庫鏈接到應(yīng)用程序中。
可選的,所述重載函數(shù)庫鏈接單元,鏈接到應(yīng)用程序中的至少包括如下內(nèi)存管理函數(shù):內(nèi)存分配函數(shù)、內(nèi)存釋放函數(shù)以及內(nèi)存調(diào)整函數(shù)。
可選的,所述重載函數(shù)庫鏈接單元,包括:靜態(tài)鏈接子單元以及動態(tài)鏈接子單元;
所述靜態(tài)鏈接子單元,用于若所述應(yīng)用程序是采用靜態(tài)鏈接的應(yīng)用程序,則在編譯時將靜態(tài)鏈接庫鏈接進應(yīng)用程序;
所述動態(tài)鏈接子單元,用于若所述應(yīng)用程序是采用動態(tài)連接的應(yīng)用程序,則在編譯時將動態(tài)鏈接庫鏈接進應(yīng)用程序或者應(yīng)用程序運行時,通過注入的方式把動態(tài)鏈接庫注入應(yīng)用程序。
可選的,所述監(jiān)控空間請求單元601,具體用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)申請內(nèi)存運行空間時,所述內(nèi)存管理函數(shù)在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間。
可選的,所述監(jiān)控空間請求單元601,具體用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)申請內(nèi)存運行空間時,所述內(nèi)存管理函數(shù)在內(nèi)存中額外請求用于記錄內(nèi)存信息的大小為16字節(jié)的標簽。
可選的,所述內(nèi)存分配信息記錄單元603,包括:判斷子單元以及內(nèi)存分配信息記錄子單元;
所述判斷子單元,用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)分配申請的內(nèi)存運行空間時,判斷所述內(nèi)存管理函數(shù)是否成功分配申請的內(nèi)存運行空間;
所述內(nèi)存分配信息記錄子單元,用于接收所述判斷子單元的判斷結(jié)果,若是,則在所述標簽中記錄本次內(nèi)存分配信息。
可選的,所述內(nèi)存分配信息記錄子單元,包括:已分配狀態(tài)設(shè)置子單元、調(diào)用棧標識設(shè)置子單元、時間設(shè)置子單元、線程標識設(shè)置子單元、桶標識設(shè)置子單元以及標簽標識設(shè)置子單元;
所述已分配狀態(tài)設(shè)置子單元,用于將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已分配狀態(tài);
所述調(diào)用棧標識設(shè)置子單元,用于調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識;
所述時間設(shè)置子單元,用于獲取對申請的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行分配時的當前系統(tǒng)時間;
所述線程標識設(shè)置子單元,用于獲取對申請的內(nèi)存運行空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對申請的內(nèi)存運行空間進行請求的線程標識;
所述桶標識設(shè)置子單元,用于根據(jù)申請的內(nèi)存運行空間的大小,將所述內(nèi)存運行空間進行分桶操作,并按照分桶操作的順序?qū)γ總€桶設(shè)置桶標識,在所述標簽中的桶標識中記錄當前內(nèi)存大小對應(yīng)桶的桶標識;
所述標簽標識設(shè)置子單元,用于將所述標簽中的標簽標識設(shè)置為已添加標簽 的標識。
可選的,所述內(nèi)存釋放信息記錄單元605,具體用于應(yīng)用程序調(diào)用所述預(yù)設(shè)的重載函數(shù)庫中的內(nèi)存管理函數(shù)釋放申請的內(nèi)存運行空間時,在所述標簽中記錄本次內(nèi)存釋放信息。
可選的,所述內(nèi)存釋放信息記錄單元605,包括:已釋放狀態(tài)設(shè)置子單元、調(diào)用棧標識設(shè)置子單元、釋放時間設(shè)置子單元、線程標識更新子單元以及標簽標識添加子單元;
所述已釋放狀態(tài)設(shè)置子單元,用于將所述標簽中的內(nèi)存塊狀態(tài)設(shè)置為已釋放狀態(tài);
所述調(diào)用棧標識設(shè)置子單元,用于調(diào)用回溯函數(shù)獲取函數(shù)調(diào)用棧的標識,將所述標簽中的內(nèi)存分配棧標識設(shè)置為通過回溯函數(shù)獲取的內(nèi)存塊的釋放函數(shù)調(diào)用棧的標識;
所述釋放時間設(shè)置子單元,用于獲取對申請的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間,將所述標簽中的時間戳設(shè)置為獲取的內(nèi)存運行空間進行釋放時的當前系統(tǒng)時間;
所述線程標識更新子單元,用于獲取對釋放的內(nèi)存空間進行請求的線程標識,將所述標簽中的線程標識設(shè)置為獲取的對釋放的內(nèi)存空間進行請求的線程標識;
所述標簽標識添加子單元,用于將所述標簽中的標簽標識設(shè)置為已添加標簽的標識。
可選的,所述調(diào)用棧標識設(shè)置子單元,具體用于采用編譯器開關(guān)記錄回溯函數(shù)獲取的函數(shù)調(diào)用棧的標識。
可選的,所述調(diào)用棧標識設(shè)置子單元,包括:
跟蹤函數(shù)調(diào)用子單元,用于在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù);
標識獲取子單元,用于通過棧記錄所述跟蹤函數(shù)調(diào)用返回地址,并通過回溯函數(shù)匯總棧信息獲取調(diào)用棧的標識。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:狀態(tài)判斷單元、內(nèi)存釋放信息記錄觸發(fā)單元以及終止函數(shù)調(diào)用單元;
所述狀態(tài)判斷單元,用于在所述標簽中記錄本次內(nèi)存釋放信息之前,判斷所述標簽中的內(nèi)存塊狀態(tài)是否為已分配狀態(tài);
所述內(nèi)存釋放信息記錄觸發(fā)單元,用于接收所述狀態(tài)判斷單元的判斷結(jié)果,若是,則執(zhí)觸發(fā)所述內(nèi)存釋放信息記錄單元;
所述終止函數(shù)調(diào)用單元,用于接收所述狀態(tài)判斷單元的判斷結(jié)果,若否,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:條件設(shè)置單元、條件判斷單元、終止函數(shù)調(diào)用單元以及標識接收觸發(fā)單元;
所述條件設(shè)置單元,用于在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)之前,在所述跟蹤函數(shù)中預(yù)設(shè)內(nèi)存寫壞的判斷條件;
所述條件判斷單元,用于在所述在每個函數(shù)調(diào)用的出入口調(diào)用跟蹤函數(shù)之后,判斷內(nèi)存塊是否滿足預(yù)設(shè)內(nèi)存寫壞的判斷條件;
所述終止函數(shù)調(diào)用單元,用于接收所述條件判斷單元的判斷結(jié)果,若是,則調(diào)用終止函數(shù)結(jié)束該應(yīng)用程序,并轉(zhuǎn)儲保存進程信息;
所述標識接收觸發(fā)單元,用于接收所述條件判斷單元的判斷結(jié)果,若否,則觸發(fā)所述標識接收子單元。
可選的,所述內(nèi)存分配信息記錄單元603,還包括:子進程創(chuàng)建子單元;
所述子進程創(chuàng)建子單元,用于在所述對申請的內(nèi)存運行空間進行分配或釋放時,根據(jù)在應(yīng)用程序中已經(jīng)運行的進程的內(nèi)存鏡像信息,創(chuàng)建與該進程資源相同的子進程。
可選的,所述監(jiān)控應(yīng)用程序內(nèi)存的裝置,還包括:內(nèi)存信息獲取單元;
所述內(nèi)存信息獲取單元,用于當應(yīng)用程序發(fā)生異常時,調(diào)用終止函數(shù)使子進程終止運行,并轉(zhuǎn)存進程信息獲取應(yīng)用程序的內(nèi)存布局。
在上述的實施例中,提供了一種監(jiān)控應(yīng)用程序內(nèi)存的方法以及一種監(jiān)控應(yīng)用程序內(nèi)存的裝置,此外,本申請還提供了一種電子設(shè)備;所述電子設(shè)備實施例如下:
請參考圖7,其示出了根據(jù)本申請的實施例提供的電子設(shè)備的示意圖。
所述電子設(shè)備,包括:顯示器701;處理器703;存儲器705;
所述存儲器705,用于存儲內(nèi)存監(jiān)控程序,所述程序在被所述處理器讀取執(zhí)行時,執(zhí)行如下操作:應(yīng)用程序申請內(nèi)存運行空間時,在內(nèi)存中額外請求預(yù)設(shè)大小的內(nèi)存監(jiān)控空間;對申請的內(nèi)存運行空間進行分配時,在額外請求的內(nèi)存監(jiān) 控空間中記錄本次內(nèi)存分配信息;對申請的內(nèi)存運行空間進行釋放時,在額外請求的內(nèi)存監(jiān)控空間中記錄本次內(nèi)存釋放信息。
在一個典型的配置中,計算設(shè)備包括一個或多個處理器(cpu)、輸入/輸出接口、網(wǎng)絡(luò)接口和內(nèi)存。
內(nèi)存可能包括計算機可讀介質(zhì)中的非永久性存儲器,隨機存取存儲器(ram)和/或非易失性內(nèi)存等形式,如只讀存儲器(rom)或閃存(flashram)。內(nèi)存是計算機可讀介質(zhì)的示例。
1、計算機可讀介質(zhì)包括永久性和非永久性、可移動和非可移動媒體可以由任何方法或技術(shù)來實現(xiàn)信息存儲。信息可以是計算機可讀指令、數(shù)據(jù)結(jié)構(gòu)、程序的模塊或其他數(shù)據(jù)。計算機的存儲介質(zhì)的例子包括,但不限于相變內(nèi)存(pram)、靜態(tài)隨機存取存儲器(sram)、動態(tài)隨機存取存儲器(dram)、其他類型的隨機存取存儲器(ram)、只讀存儲器(rom)、電可擦除可編程只讀存儲器(eeprom)、快閃記憶體或其他內(nèi)存技術(shù)、只讀光盤只讀存儲器(cd-rom)、數(shù)字多功能光盤(dvd)或其他光學存儲、磁盒式磁帶,磁帶磁磁盤存儲或其他磁性存儲設(shè)備或任何其他非傳輸介質(zhì),可用于存儲可以被計算設(shè)備訪問的信息。按照本文中的界定,計算機可讀介質(zhì)不包括非暫存電腦可讀媒體(transitorymedia),如調(diào)制的數(shù)據(jù)信號和載波。
2、本領(lǐng)域技術(shù)人員應(yīng)明白,本申請的實施例可提供為方法、系統(tǒng)或計算機程序產(chǎn)品。因此,本申請可采用完全硬件實施例、完全軟件實施例或結(jié)合軟件和硬件方面的實施例的形式。而且,本申請可采用在一個或多個其中包含有計算機可用程序代碼的計算機可用存儲介質(zhì)(包括但不限于磁盤存儲器、cd-rom、光學存儲器等)上實施的計算機程序產(chǎn)品的形式。
本申請雖然以較佳實施例公開如上,但其并不是用來限定本申請,任何本領(lǐng)域技術(shù)人員在不脫離本申請的精神和范圍內(nèi),都可以做出可能的變動和修改,因此本申請的保護范圍應(yīng)當以本申請權(quán)利要求所界定的范圍為準。