專利名稱:一種自適應(yīng)動態(tài)代碼卸載方法
技術(shù)領(lǐng)域:
本發(fā)明屬于Java虛擬機設(shè)計技術(shù)領(lǐng)域,具體涉及一種自適應(yīng)動態(tài)代碼卸載方法, 包括代碼生成、代碼管理和垃圾回收等。
背景技術(shù):
如今,手機、平板電腦等嵌入式設(shè)備等正在步入一個空前繁榮的時代,運行在這些設(shè)備上的程序性能直接關(guān)系到用戶體驗,決定著相應(yīng)產(chǎn)品的市場控制力,也影響著技術(shù)發(fā)展的方向和進程。程序的性能一方面取決于程序本身的實現(xiàn),另一方面也來自于對設(shè)備資源的高效合理的利用。對于嵌入式設(shè)備而言,由于成本的影響,它們的硬件資源往往比個人電腦(PC)更為有限。因此,高效的資源管理技術(shù)對嵌入式設(shè)備而言顯得更為重要。內(nèi)存管理是計算機中的一項重要技術(shù)。對于虛擬機而言,垃圾回收是內(nèi)存管理的成熟機制。垃圾回收器通常需要對虛擬機的堆內(nèi)存進行整理、回收,壓縮,移動等操作,以實現(xiàn)有限內(nèi)存的合理利用。內(nèi)存管理除了管理應(yīng)該程序所申請的內(nèi)存之外,還包括虛擬機為編譯程序而申請的代碼存儲內(nèi)存。即時編譯器(Just-In-Time Compiler,JIT)是虛擬機用來將字節(jié)碼編譯為機制碼的組件,其實現(xiàn)字節(jié)碼向機器碼轉(zhuǎn)變的過程被稱為代碼生成過程。經(jīng)過代碼生成過程得到程序機器碼其本質(zhì)上是一組連續(xù)的帶有機器指令編碼的內(nèi)存。 在執(zhí)行這些指令之前,虛擬機為這些指令分配內(nèi)存空間,然后將指令載入內(nèi)存,讀取指令至 CPU相應(yīng)電子以執(zhí)行。通常情況下,即時編譯器生成的機制碼所占空間會比原有字節(jié)碼所占空間增加六倍以上,這種現(xiàn)象被稱為代碼膨脹。對于硬件資源豐富的設(shè)備而言,代碼膨脹對設(shè)備上運行程序的性能的影響可能不大,但是,對于嵌入式設(shè)備而言,代碼膨脹所增加的內(nèi)存需求對程序的性能有很大影響。為了更好地利用有限的內(nèi)存資源,通過分析程序方法的調(diào)用特性,人們提出了代碼卸載(Code Unloading)技術(shù)。當(dāng)應(yīng)用程序所需內(nèi)存達到某一個臨界值時,虛擬機就應(yīng)該考慮對內(nèi)存進行回收,代碼卸載即在此時發(fā)生。在應(yīng)用程序運行過程中,并不是所有的方法都會被執(zhí)行到,相反,很多方法都不會被執(zhí)行或者只被執(zhí)行一次或幾次(這些方法稱為“冷方法”),更多的程序執(zhí)行時間被用來反復(fù)執(zhí)行為數(shù)不多的幾個方法(稱為“熱方法”)。對于冷方法,虛擬機在代碼卸載時將其所占用的內(nèi)存釋放或移至外存,以便將更多的熱方法載入內(nèi)存,以減少由于內(nèi)存容量有限致使熱方法的反復(fù)加載而增加的時間消耗,從而提升程序的性能,改善用戶體驗。代碼卸載需要合理的方法淘汰策略,如果策略得當(dāng),移出的方法為更熱的方法提供更多的內(nèi)存,就能減少熱方法的反復(fù)加載,使程序更快的執(zhí)行;如果策略失當(dāng),移出的方法隨后又被多次調(diào)用,或者移入的方法不是真正的熱方法,那么進行代碼卸載所需的開銷作用明顯,反而使程序執(zhí)行時間變長。因此,符合所運行程序行為的卸載策略非常重要,而要做到較為準確地分析程序的運行時行為,就必須獲得程序的運行時數(shù)據(jù),即動態(tài)數(shù)據(jù),并在此基礎(chǔ)上實現(xiàn)可以自適應(yīng)的代碼卸載機制。目前常見的動態(tài)尋找熱方法的技術(shù)是程序剖析(Profiling),通常借助插樁(Instrumentation)和采樣(Sampling)兩種方式。前者需要在源程序中添加剖析代碼,用以統(tǒng)計方法被調(diào)用的次數(shù);后者雖然不需要修改源程序,但需要每隔一定時間對程序的方法棧進行掃描以獲得當(dāng)前正在執(zhí)行的方法。兩種方式都需要一定的額外開銷,屬于重量級的剖析方法。然而,這些重量級的方法在嵌入式設(shè)備,尤其是資源受限的嵌入式設(shè)備不適用。在這些設(shè)備上,能否實現(xiàn)不進行重量級剖析而又能較為準確地反應(yīng)程序的動態(tài)行為的剖析方法對于代碼卸載就顯得至關(guān)重要。
發(fā)明內(nèi)容
本發(fā)明的目的在于提供一種能夠減少程序剖析開銷、提高程序執(zhí)行速度的動態(tài)自適應(yīng)代碼卸載方法,并在Android操作系統(tǒng)內(nèi)置虛擬機Dalvik上將其實現(xiàn)。本發(fā)明調(diào)研了運行于Android操作系統(tǒng)之上的Java虛擬機中垃圾回收器,發(fā)現(xiàn)在進行內(nèi)存回收過程中,回收器會遍歷當(dāng)前棧上每個方法;并試驗發(fā)現(xiàn),熱方法的棧幀經(jīng)常在垃圾回收時進行的棧遍歷中被訪問,而冷方法的棧幀在棧遍歷時出現(xiàn)的頻率很小。這些發(fā)現(xiàn)表明,方法的熱度與其在棧上出現(xiàn)的頻率有關(guān)系。通過分析,我們?nèi)菀椎贸鲈跅1闅v時被訪問次數(shù)多的方法很可能是熱方法;或者說,緊挨著兩次垃圾回收過程上,都沒有出現(xiàn)在棧上的方法不是熱方法的可能性比較大。這與程序運行的特征有關(guān)系,但是,多數(shù)情況下, 因為熱方法被調(diào)用的頻率很高,因此其在棧上出現(xiàn)的次數(shù)也多。因此,本發(fā)明不使用前面所述的采樣或插樁的剖析方法,而將類似采樣的邏輯嵌入到垃圾回收執(zhí)行的過程中,這樣就消除了剖析所需的開銷。垃圾回收越是頻繁,即觸發(fā)越頻繁、觸發(fā)相隔時間越短,說明程序?qū)?nèi)存的需求越大,則熱方法越是集中,越是可能出現(xiàn)在前后兩次棧遍歷中。本發(fā)明采用的技術(shù)方案為設(shè)置一個方法卸載狀態(tài)機,并為每一個方法設(shè)置卸載狀態(tài);在垃圾回收過程中,進行棧遍歷;在棧遍歷的過程中同時實現(xiàn)方法狀態(tài)按狀態(tài)機遷移;在垃圾回收結(jié)束前,依據(jù)方法當(dāng)前的狀態(tài)決定對方法進行卸載與否。本發(fā)明方法分為三個階段方法棧遍歷,方法狀態(tài)遷移和代碼卸載。在方法棧遍歷階段同,本發(fā)明從虛擬機棧上獲得每個方法的棧幀數(shù)據(jù)。在方法狀態(tài)遷移階段,本發(fā)明依據(jù)所設(shè)計的狀態(tài)機、通過第一階段得到的方法棧信息進一步獲得的方法當(dāng)前卸載狀態(tài)以及方法在垃圾回收過程中是否被掃描信息,做出正確的方法卸載狀態(tài)遷移。在代碼卸載階段,虛擬機遍歷整個方法列表,獲取每個方法的卸載狀態(tài),如果其狀態(tài)滿足狀態(tài)機所設(shè)定的終止態(tài),則對方法的代碼進行卸載,將其所占內(nèi)存釋放。圖1展示了該方案的流程圖。下面詳述本發(fā)明的完整過程,在程序運行過程中,虛擬機對內(nèi)存使用量進行監(jiān)控,當(dāng)內(nèi)存使用量沒有超過一個設(shè)定的閥值(Threshold)時,程序不會觸發(fā)代碼卸載功能;當(dāng)使用量超過閥值時, 虛擬機隨即進入代碼卸載。下面分別進一步具體介紹。1、棧遍歷,這是本發(fā)明的第一階段。如圖1中“棧掃描”階段所示,程序使用內(nèi)存量超過閥值(臨界值)后,代碼卸載啟動第一步,棧掃描。本發(fā)明使用虛擬機已有的棧掃描技術(shù),通過棧指針信息獲得每個方法棧幀的數(shù)據(jù)。這些數(shù)據(jù)為下一階段提供數(shù)據(jù)操作接口。2、狀態(tài)遷移,這是本發(fā)明的第二階段。該階段由兩次遷移組成,分別由圖2中實線與虛線表示。第一次遷移發(fā)生在完成對每個棧幀掃描結(jié)束之前,過程如圖2中虛線所示。每個方法的初始狀態(tài)都設(shè)置為圖2中的“初始態(tài)”,如果方法在棧上被掃描到,則方法狀態(tài)變?yōu)椤耙褣呙琛?;如果該方法在本次掃描過程中在棧上出現(xiàn)多次,則其狀態(tài)會停留在“已掃描”; 如果該方法在上一次掃描時狀態(tài)設(shè)置為“即將卸載”,那么這次掃描,該方法再次被掃描到,其狀態(tài)就還原為“初始態(tài)”。本發(fā)明根據(jù)上文調(diào)研結(jié)果,作出合理假設(shè),即如果一個方法在連續(xù)兩次棧掃描中都沒有出現(xiàn),則其可能在最近一段時間內(nèi)不是熱方法,其是成為被卸載方法的候選。因此,本發(fā)明設(shè)計了第二次遷移,實現(xiàn)對連續(xù)兩次沒有被掃描到的方法卸載。第二次遷移發(fā)生在代碼卸載之前,過程如圖2中實線所示。本次遷移與第一次不同,其對象為所有方法。對于在第一階段掃描到方法,其狀態(tài)為“初始態(tài)”或者“已掃描”,依據(jù)圖2,這些方法在此次不會被卸載;對于沒有掃描到的方法,其狀態(tài)為上一次該方法被掃描到時設(shè)置的狀態(tài),依據(jù)圖2實線箭頭,如果該方法狀態(tài)為“即將卸載”,則該方法狀態(tài)遷移為“已卸載”; 如果為“初始態(tài)”則遷移為“即將卸載”,“已掃描”遷移為“初始態(tài)”。3、代碼卸載,這是本發(fā)明的第三階段。如圖1 “代碼卸載”所示,根據(jù)第二階段對方法的狀態(tài)標識,遍歷整個方法列表,對所有狀態(tài)為“已卸載”的方法進行代碼卸載。已卸載的方法狀態(tài)將持續(xù)為“已卸載”直到其被重新編譯,重新編譯后,方法狀態(tài)被重新設(shè)置為 “初始態(tài)”。代碼卸載后的方法,其代碼空間將被釋放,從而給其他的方法或者數(shù)據(jù)使用。本發(fā)明的有益效果是1)本發(fā)明設(shè)計實現(xiàn)了一個動態(tài)自適應(yīng)代碼卸載機制。2)本發(fā)明無需對程序進行重量級的剖析,只需對垃圾回收稍做修改,消除了程序剖析所需的花銷。3)本發(fā)明使應(yīng)用程序的內(nèi)存需求量降低,使得很多因內(nèi)存足跡(memory footprint)過大而難以在內(nèi)存有限的設(shè)備上運行的程序得以在其上運行。4)本發(fā)明尋找熱方法的策略可以推廣至虛擬機其他功能組件,使其他組件減少程序剖析的開銷,從而發(fā)現(xiàn)更多的優(yōu)化機石。
圖1為本發(fā)明所述代碼卸載機制的流程設(shè)計圖。圖2為棧掃描與代碼卸載共同作用下的方法卸載狀態(tài)機設(shè)計圖。
具體實施例方式在具體實施過程中,我們發(fā)現(xiàn)本發(fā)明的第二個階段(狀態(tài)遷移)的第一次遷移可以與第一個階段整合實現(xiàn),從而減少一次為設(shè)置方法狀態(tài)而進行的棧掃描;同樣,第二次遷移可以與第三個階段整合實現(xiàn),從而減少一次為設(shè)置方法狀態(tài)而進行的整個方法列表掃描。 因此,在具體實施時,我們選擇將第二階段的兩次遷移結(jié)合到第一階段和第三階段中,從而使實現(xiàn)更加高效。下面將以時間順序介紹本發(fā)明方法的二個步驟的詳細實現(xiàn)。步驟一、棧掃描與第一次狀態(tài)遷移
本步驟目的在于依次掃描每個棧幀,得到操作每個棧幀所屬方法的操作接口,再利用該接口設(shè)置方法的卸載狀態(tài)。本發(fā)明使用虛擬機內(nèi)置的棧掃描方法,在掃描過程中,得到每個棧幀所屬方法的方法指針,結(jié)合圖2所示狀態(tài)機,設(shè)置方法的卸載狀態(tài)。方法的卸載狀態(tài)包括以下四種初始態(tài)、已掃描、即將卸載和已卸載。每個方法的卸載狀態(tài)在方法加載時被設(shè)置為初始態(tài),如果在棧掃描過程中,某個方法存在于棧上(即被掃描到),那么它的狀態(tài)將按照圖2中所示的虛線箭頭指示進行遷移。按照狀態(tài)機所示,如果一個方法處于“初始態(tài)”,且被掃描到,那么它的狀態(tài)會立即被置為“已掃描”;如果一個方法在前一次垃圾回收中未被掃描到,即其當(dāng)前狀態(tài)為“即將卸載”,但是在此次垃圾回收棧掃描時被掃描,那么該方法的卸載狀態(tài)會被還原為“初始態(tài)”;如果一個方法(遞歸方法或者在垃圾回收發(fā)生時,在多個線程上同時執(zhí)行的方法)在此次掃描中出現(xiàn)多次,那么該方法的卸載狀態(tài)將保持在“已掃描”狀態(tài)。棧掃描方法的偽代碼如圖3中scanMethod所示,其算法思想如下
1)初始化方法卸載狀態(tài)為初始態(tài)
2)棧掃描對棧上每個方法
a)如果方法的卸載狀態(tài)為初始態(tài),則將其修改為已掃描;
b)如果方法的卸載狀態(tài)為已掃描態(tài),則將其修改為已掃描態(tài);
c)如果方法的卸載狀態(tài)為即將卸載態(tài),則將其修改為初始態(tài);
從上述算法思想可以看到,當(dāng)一個方法被掃描到時,其狀態(tài)按圖2所示狀態(tài)機從左到右依次做一回遷移。需要說明的是,如圖2中虛線箭頭所示的狀態(tài)遷移并不是一個完整地狀態(tài)機。因為圖中虛線箭頭至少沒有終止狀態(tài)。完整的狀態(tài)變換還需要下一步驟的介入。步驟二、代碼卸載與第二次狀態(tài)遷移
經(jīng)過步驟一,被掃描到的方法的卸載狀態(tài)已經(jīng)發(fā)生了改變,沒有被掃描到的方法則保持其原有狀態(tài)。依據(jù)方法的最后狀態(tài),本發(fā)明選擇在掃描之后垃圾回收結(jié)束之前對方法進行卸載。卸載的過程的偽代碼如附錄中第二個方法performCodeUnload所示,其算法思想為
對于方法列表中的每個方法
1)如果該方法的卸載狀態(tài)為即將卸載,則將方法的機器碼地址修改為引導(dǎo)重編譯的代碼片段(Code Stub)的地址,將代碼的卸載狀態(tài)修改為已卸載,并將代碼所占內(nèi)存地址釋放;
2)如果方法的卸載狀態(tài)為初始態(tài),則將其修改為即將卸載;
3)如果方法的卸載狀態(tài)為已掃描,則將其修改為初始態(tài)。從上述算法思想可以看到1)此次掃描到的方法必定不會被回收;2)此次垃圾回收沒有掃描到的方法,如果其狀態(tài)為即將卸載,那么,該方法會立刻被卸載;3)此次掃描到的方法不會被卸載,其卸載狀態(tài)按圖2所示狀態(tài)機從右到左依次做一回遷移。附錄
Void scanMethod(Method* method){
if(method->status == METH0D_T0_UNL0AD)
method->status = METH0D_INITIAL;
else if(method->status == METH0D_INITIAL)
method->status= METH0D_SCANED;
else if(method->status == METH0D_SCANED)
method->status = METH0D_SCANED;
}
VoidperformCodeUnload(){
Method* method = startMethod\ while ( method != NULL){
if(method->status == METH0D_T0_UNL0AD){//unload this method method->codeAddr = (void氺)codeStub; method->status = METH0D_UNL0ADED;free(method->alIocatedAddr); //recycle of code memory
ι
else if(method->status == METHOD_INITIAL) method->status = METH0D_T0_UNL0AD; else if(method->status == METHOD_SCANED) method->status = METHOD_INITIAL;
method = nextMethod\
權(quán)利要求
1.一種自適應(yīng)動態(tài)代碼卸載方法,其特征在于分為三個階段方法棧遍歷、方法狀態(tài)遷移和代碼卸載;在方法棧遍歷階段,從虛擬機棧上獲得每個方法的棧幀數(shù)據(jù);在方法狀態(tài)遷移階段,依據(jù)所設(shè)計的狀態(tài)機、通過第一階段得到的方法棧信息進一步獲得的方法當(dāng)前卸載狀態(tài)以及方法在垃圾回收過程中是否被掃描信息,做出正確的方法卸載狀態(tài)遷移;在代碼卸載階段, 虛擬機遍歷整個方法列表,獲取每個方法的卸載狀態(tài),如果其狀態(tài)滿足狀態(tài)機所設(shè)定的終止態(tài),則對方法的代碼進行卸載,將其所占內(nèi)存釋放。
2.根據(jù)權(quán)利要求1所述的自適應(yīng)動態(tài)代碼卸載方法,其特征在于所述方法棧遍歷,是在程序使用內(nèi)存量超過閥值后啟動,使用虛擬機已有的棧掃描技術(shù),通過棧指針信息獲得每個方法棧幀的數(shù)據(jù),這些數(shù)據(jù)為下一階段提供數(shù)據(jù)操作接口。
3.根據(jù)權(quán)利要求2所述的自適應(yīng)動態(tài)代碼卸載方法,其特征在于所述方法狀態(tài)遷移由兩次遷移組成;第一次遷移發(fā)生在完成對每個棧幀掃描結(jié)束之前,每個方法的初始狀態(tài)都設(shè)置為“初始態(tài)”,如果方法在棧上被掃描到,則方法狀態(tài)變?yōu)椤耙褣呙琛?;如果該方法在本次掃描過程中在棧上出現(xiàn)多次,則其狀態(tài)會停留在“已掃描”;如果該方法在上一次掃描時狀態(tài)設(shè)置為 “即將卸載”,那么這次掃描,該方法再次被掃描到,其狀態(tài)就還原為“初始態(tài)”;第二次遷移發(fā)生在代碼卸載之前,本次遷移的對象為所有方法;對于在第一階段掃描到方法,其狀態(tài)為“初始態(tài)”或者“已掃描”,這些方法在此次不會被卸載;對于沒有掃描到的方法,其狀態(tài)為上一次該方法被掃描到時設(shè)置的狀態(tài),如果該方法狀態(tài)為“即將卸載”,則該方法狀態(tài)遷移為“已卸載”;如果為“初始態(tài)”則遷移為“即將卸載”,“已掃描”遷移為“初始態(tài)”。
4.根據(jù)權(quán)利要求3所述的自適應(yīng)動態(tài)代碼卸載方法,其特征在于所述代碼卸載,是根據(jù)第二階段對方法的狀態(tài)標識,遍歷整個方法列表,對所有狀態(tài)為“已卸載”的方法進行代碼卸載;已卸載的方法狀態(tài)將持續(xù)為“已卸載”直到其被重新編譯,重新編譯后,方法狀態(tài)被重新設(shè)置為“初始態(tài)”;代碼卸載后的方法,其代碼空間被釋放,給其他的方法或者數(shù)據(jù)使用。
全文摘要
本發(fā)明屬于Java虛擬機設(shè)計技術(shù)領(lǐng)域,具體為一種自適應(yīng)動態(tài)代碼卸載方法。該方法包括方法棧遍歷,從虛擬機棧上獲得每個方法的棧幀數(shù)據(jù);方法狀態(tài)遷移,依據(jù)所設(shè)計的狀態(tài)機和得到的方法棧信息,做出正確的方法卸載狀態(tài)遷移;代碼卸載,虛擬機遍歷整個方法列表,獲取每個方法的卸載狀態(tài),如果其狀態(tài)滿足狀態(tài)機所設(shè)定的終止態(tài),則對方法的代碼進行卸載,將其所占內(nèi)存釋放。本發(fā)明借助已有的垃圾回收機制,在垃圾回收過程中動態(tài)獲取方法的狀態(tài),根據(jù)用戶設(shè)置自適應(yīng)地實現(xiàn)方法的卸載,消除了為獲得較為準確的熱、冷方法而進行程序剖析的額外開銷,提高了程序執(zhí)行速度,并且獲得了比較好的代碼卸載效果。
文檔編號G06F9/445GK102243596SQ20111022709
公開日2011年11月16日 申請日期2011年8月9日 優(yōu)先權(quán)日2011年8月9日
發(fā)明者周波, 張源, 楊珉 申請人:復(fù)旦大學(xué)