国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

JVM、Dalvik VM和ART虛擬機(jī)之間的區(qū)別

2019-11-09 17:14:36
字體:
供稿:網(wǎng)友
Android系統(tǒng)使用Dalvik Virtual Machine (DVM)作為其虛擬機(jī),所有安卓程序都運(yùn)行在安卓系統(tǒng)進(jìn)程里,每個進(jìn)程對應(yīng)著一個Dalvik虛擬機(jī)實(shí)例。他們都提供了對象生命周期管理、堆棧管理、線程管理、安全和異常管理以及垃圾回收等重要功能,各自擁有一套完整的指令系統(tǒng)。Android之所以不直接使用JVM作為其虛擬機(jī)的原因有很多,版權(quán)問題我們暫且擱置一邊,本文將首先在技術(shù)上對DVM和JVM進(jìn)行比較,然后重點(diǎn)對Dalvik虛擬機(jī)的垃圾回收機(jī)制進(jìn)行介紹,文章末尾再對Android5.0之后使用的新型虛擬機(jī)——ART虛擬機(jī)進(jìn)行簡單介紹。

DVM vs JVM

共同點(diǎn):

都是解釋執(zhí)行都是每個 OS 進(jìn)程運(yùn)行一個 VM,并運(yùn)行一個單獨(dú)的程序在較新版本中(Froyo / Sun JDK 1.5)都實(shí)現(xiàn)了相當(dāng)程度的 JIT compiler(即時編譯) 用于提速。 JIT(Just In Time,即時編譯技術(shù))對于熱代碼(使用頻率高的字節(jié)碼)直接轉(zhuǎn)換成匯編代碼;

不同點(diǎn):

dvm執(zhí)行的是.dex格式文件,jvm執(zhí)行的是.class文件。class文件和dex之間可以相互轉(zhuǎn)換具體流程如下圖,多個class文件轉(zhuǎn)變成一個dex文件會引發(fā)一些問題,具體如下: 方法數(shù)受限:多個class文件變成一個dex文件所帶來的問題就是方法數(shù)超過65535時報錯,由此引出MultiDex技術(shù),具體資料同學(xué)可以google下。class文件去冗余:class文件存在很多的冗余信息,dex工具會去除冗余信息(多個class中的字符串常量合并為一個,比如對于Ljava/lang/Oject字符常量,每個class文件基本都有該字符常量,存在很大的冗余),并把所有的.class文件整合到.dex文件中。減少了I/O操作,提高了類的查找速度。 許多GC實(shí)現(xiàn)都是在對象開頭的地方留一小塊空間給GC標(biāo)記用。Dalvik VM則不同,在進(jìn)行GC的時候會單獨(dú)申請一塊空間,以位圖的形式來保存整個堆上的對象的標(biāo)記,在GC結(jié)束后就釋放該空間。 (關(guān)于這一點(diǎn)后面的Dalvik垃圾回收機(jī)制還會更加深入的介紹)dvm是基于寄存器的虛擬機(jī) 而jvm執(zhí)行是基于虛擬棧的虛擬機(jī)。這類的不同是最要命的,因?yàn)樗鼘?dǎo)致一系列的問題,具體如下: dvm速度快!寄存器存取速度比棧快的多,dvm可以根據(jù)硬件實(shí)現(xiàn)最大的優(yōu)化,比較適合移動設(shè)備。JAVA虛擬機(jī)基于棧結(jié)構(gòu),程序在運(yùn)行時虛擬機(jī)需要頻繁的從棧上讀取寫入數(shù)據(jù),這個過程需要更多的指令分派與內(nèi)存訪問次數(shù),會耗費(fèi)很多CPU時間。指令數(shù)小!dvm基于寄存器,所以它的指令是二地址和三地址混合,指令中指明了操作數(shù)的地址;jvm基于棧,它的指令是零地址,指令的操作數(shù)對象默認(rèn)是操作數(shù)棧中的幾個位置。這樣帶來的結(jié)果就是dvm的指令數(shù)相對于jvm的指令數(shù)會小很多,jvm需要多條指令而dvm可能只需要一條指令。jvm基于棧帶來的好處是可以做的足夠簡單,真正的跨平臺,保證在低硬件條件下能夠正常運(yùn)行。而dvm操作平臺一般指明是ARM系統(tǒng),所以采取的策略有所不同。需要注意的是dvm基于寄存器,但是這也是個映射關(guān)系,如果硬件沒有足夠的寄存器,dvm將多出來的寄存器映射到內(nèi)存中。 

Dalvik虛擬機(jī)

談到垃圾回收自然而然的想到了堆,Dalvik的堆結(jié)構(gòu)相對于JVM的堆結(jié)構(gòu)有所區(qū)別,這主要體現(xiàn)在Dalvik將堆分成了Active堆和Zygote堆,這里大家只要知道Zygote堆是Zygote進(jìn)程在啟動的時候預(yù)加載的類、資源和對象(具體gygote進(jìn)程預(yù)加載了哪些類,詳見文末的附錄),除此之外的所有對象都是存儲在Active堆中的。對于為何要將堆分成gygote和Active堆,這主要是因?yàn)锳ndroid通過fork方法創(chuàng)建到一個新的gygote進(jìn)程,為了盡可能的避免父進(jìn)程和子進(jìn)程之間的數(shù)據(jù)拷貝,fork方法使用寫時拷貝技術(shù),寫時拷貝技術(shù)簡單講就是fork的時候不立即拷貝父進(jìn)程的數(shù)據(jù)到子進(jìn)程中,而是在子進(jìn)程或者父進(jìn)程對內(nèi)存進(jìn)行寫操作時是才對內(nèi)存內(nèi)容進(jìn)行復(fù)制,Dalvik的gygote堆存放的預(yù)加載的類都是Android核心類和java運(yùn)行時庫,這部分內(nèi)容很少被修改,大多數(shù)情況父進(jìn)程和子進(jìn)程共享這塊內(nèi)存區(qū)域。通常垃圾回收重點(diǎn)對Active堆進(jìn)行回收操作,Dalvik為了對堆進(jìn)行更好的管理創(chuàng)建了一個Card Table、兩個Heap Bitmap和一個Mark Stack數(shù)據(jù)結(jié)構(gòu)。

Dalvik創(chuàng)建對象流程

當(dāng)Dalvik虛擬機(jī)的解釋器遇到一個new指令時,它就會調(diào)用函數(shù)Object* dvmAllocObject(ClassObject* clazz, int flags)。期間完成的動作有( 注意:Java堆分配內(nèi)存前后,要對Java堆進(jìn)行加鎖和解鎖,避免多個線程同時對Java堆進(jìn)行操作。下面所說的堆指的是Active堆): 調(diào)用函數(shù)dvmHeapSourceAlloc在Java堆上分配指定大小的內(nèi)存,成功則返回,否則下一步。執(zhí)行一次GC, GC執(zhí)行完畢后,再次調(diào)用函數(shù)dvmHeapSourceAlloc在Java堆上分配指定大小的內(nèi)存,成功則返回,否則下一步。首先將堆的當(dāng)前大小設(shè)置為Dalvik虛擬機(jī)啟動時指定的Java堆最大值,然后進(jìn)行內(nèi)存分配,成功返回失敗下一步。這里調(diào)用的函數(shù)是 dvmHeapSourceAllocAndGrow調(diào)用函數(shù)gcForMalloc來執(zhí)行GC,這里的GC和第二步的GC,區(qū)別在于這里回收軟引用對象引用的對象,如果還是失敗拋出OOM異常。這里調(diào)用的函數(shù)是dvmHeapSourceAllocAndGrow

Dalvik回收對象流程

Dalvik的垃圾回收策略默認(rèn)是標(biāo)記擦除回收算法,即Mark和Sweep兩個階段。標(biāo)記與清理的回收算法一個明顯的區(qū)別就是會產(chǎn)生大量的垃圾碎片,因此程序中應(yīng)該避免有大量不連續(xù)小碎片的時候分配大對象,同時為了解決碎片問題,Dalvik虛擬機(jī)通過使用dlmalloc技術(shù)解決,關(guān)于后者讀者另行g(shù)oogle。下面我們對Mark階段進(jìn)行簡單介紹。Mark階段使用了兩個Bitmap來描述堆的對象,一個稱為Live Bitmap,另一個稱為Mark Bitmap。Live Bitmap用來標(biāo)記上一次GC時被引用的對象,也就是沒有被回收的對象,而Mark Bitmap用來標(biāo)記當(dāng)前GC有被引用的對象。當(dāng)Live Bitmap被標(biāo)記為1,但是在Mark Bitmap中標(biāo)記為0的對象表明該對象需要被回收。此外在Mark階段往往要求其它線程處于停止?fàn)顟B(tài),因此Mark又分為并行和串行兩種方式,并行的Mark分為兩個階段:1)、只標(biāo)記gc_root對象,即在GC開始的瞬間被全局變量、棧變量、寄存器等所引用的對象,該階段不允許垃圾回收線程之外的線程處于運(yùn)行狀態(tài)。2)、有條件的并行運(yùn)行其它線程,使用Card Table記錄在垃圾收集過程中對象的引用情況。整個Mark 階段都是通過Mark Stack來實(shí)現(xiàn)遞歸檢查被引用的對象,即在當(dāng)前GC中存活的對象。標(biāo)記過程類似用一個棧把第一階段得到的gc_root放入棧底,然后依次遍歷它們所引用的對象(通過出棧入棧),即用棧數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)了對每個gc_root的遞歸。Dalvik的GC類型共有四種: GC_CONCURRENT: 表示是在已分配內(nèi)存達(dá)到一定量之后觸發(fā)的GC。GC_FOR_MALLOC: 表示是在堆上分配對象時內(nèi)存不足觸發(fā)的GC。GC_BEFORE_OOM: 表示是在準(zhǔn)備拋OOM異常之前進(jìn)行的最后努力而觸發(fā)的GC。GC_EXPLICIT: 表示是應(yīng)用程序調(diào)用System.gc、VMRuntime.gc接口或者收到SIGUSR1信號時觸發(fā)的GC。其中GC_FOR_MALLOC、GC_CONCURRENT和GC_BEFORE_OOM三種類型的GC都是在分配對象的過程觸發(fā)的。垃圾回收具體都是通過調(diào)用函數(shù)void dvmCollectGarbageInternal(const GcSpec* spec) 來執(zhí)行垃圾回收,該函數(shù)的參數(shù)GcSpec結(jié)構(gòu)體定義見本文的附錄。對于函數(shù)dvmCollectGarbageInternal的內(nèi)部邏輯,即垃圾回收流程,根據(jù)垃圾回收線程和工作線程的關(guān)系分為并行GC和非并行GC。前者在回收階段有選擇性的停止當(dāng)前工作線程,后者在垃圾回收階段停止所有工作線程。但是并行GC需要多執(zhí)行一次標(biāo)記根集對象以及遞歸標(biāo)記那些在GC過程被訪問了的對象的操作,意味著并行GC需要花費(fèi)更多的CPU資源。dvmCollectGarbageInternal函數(shù)的內(nèi)部邏輯如下:(本文末尾的附錄中給出了一個對應(yīng)的流程圖) 調(diào)用函數(shù)dvmSuspendAllThreads掛起所有的線程,以免它們干擾GC。 這里如何掛起其它線程呢?其實(shí)就是每個線程在運(yùn)行過程中會周期性的檢測自身的一個標(biāo)志位,通過這個標(biāo)志位我們可以告知線程停止運(yùn)行。 調(diào)用函數(shù)dvmHeapBeginMarkStep初始化Mark Stack,并且設(shè)定好GC范圍。 Mark Stack其實(shí)是一個object指針數(shù)組 調(diào)用函數(shù)dvmHeapMarkRootSet標(biāo)記根集對象。 Mark的第一階段,主要分為兩大類:1)Dalvik虛擬機(jī)內(nèi)部使用的全局對象(維護(hù)在一個hash表中);2)應(yīng)用程序正在使用的對象(維護(hù)在一個調(diào)用棧中) 調(diào)用函數(shù)dvmClearCardTable清理Card Table。(只在并行g(shù)c發(fā)生) Card Table記錄記錄在Zygote堆上分配的對象在垃圾收集執(zhí)行過程中對在Active堆上分配的對象的引用。 調(diào)用函數(shù)dvmUnlock解鎖堆。這個是針對調(diào)用函數(shù)dvmCollectGarbageInternal執(zhí)行GC前的堆鎖定操作。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmResumeAllThreads喚醒第1步掛起的線程。(只在并行g(shù)c發(fā)生) 此時非gc線程可以開始工作,這部分線程對堆的操作記錄在CardTable上面,gc則進(jìn)行Mark的第二階段 調(diào)用函數(shù)dvmHeapScanMarkedObjects從第3步獲得的根集對象開始,歸遞標(biāo)記所有被根集對象引用的對象。調(diào)用函數(shù)dvmLockHeap重新鎖定堆。這個是針對前面第5步的操作。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmSuspendAllThreads重新掛起所有的線程。這個是針對前面第6步的操作。(只在并行g(shù)c發(fā)生) 這里需要再次停止工作線程,用來解決前面線程對堆的少部分的操作,這個過程很快。 調(diào)用函數(shù)dvmHeaPReMarkRootSet更新根集對象。因?yàn)橛锌赡茉诘?步到第6步的執(zhí)行過程中,有線程創(chuàng)建了新的根集對象。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmHeapReScanMarkedObjects歸遞標(biāo)記那些在第4步到第6步的執(zhí)行過程中被修改的對象。這些對象記錄在Card Table中。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmHeapProcessReferences處理那些被軟引用(Soft Reference)、弱引用(Weak Reference)和影子引用(Phantom Reference)引用的對象,以及重寫了finalize方法的對象。這些對象都是需要特殊處理的。調(diào)用函數(shù)dvmHeapSweepSystemWeaks回收系統(tǒng)內(nèi)部使用的那些被弱引用引用的對象。調(diào)用函數(shù)dvmHeapSourceSwapBitmaps交換Live Bitmap和Mark Bitmap。 執(zhí)行了前面的13步之后,所有還被引用的對象在Mark Bitmap中的bit都被設(shè)置為1。Live Bitmap記錄的是當(dāng)前GC前還被引用著的對象。通過交換這兩個Bitmap,就可以使得當(dāng)前GC完成之后,使得Live Bitmap記錄的是下次GC前還被引用著的對象。 調(diào)用函數(shù)dvmUnlock解鎖堆。這個是針對前面第8步的操作。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmResumeAllThreads喚醒第9步掛起的線程。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmHeapSweepUnmarkedObjects回收那些沒有被引用的對象。沒有被引用的對象就是那些在執(zhí)行第14步之前,在Live Bitmap中的bit設(shè)置為1,但是在Mark Bitmap中的bit設(shè)置為0的對象。調(diào)用函數(shù)dvmHeapFinishMarkStep重置Mark Bitmap以及Mark Stack。這個是針對前面第2步的操作。調(diào)用函數(shù)dvmLockHeap重新鎖定堆。這個是針對前面第15步的操作。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmHeapSourceGrowForUtilization根據(jù)設(shè)置的堆目標(biāo)利用率調(diào)整堆的大小。調(diào)用函數(shù)dvmBroadcastCond喚醒那些等待GC執(zhí)行完成再在堆上分配對象的線程。(只在并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmResumeAllThreads喚醒第1步掛起的線程。(只在非并行g(shù)c發(fā)生)調(diào)用函數(shù)dvmEnqueueClearedReferences將那些目標(biāo)對象已經(jīng)被回收了的引用對象增加到相應(yīng)的Java隊列中去,以便應(yīng)用程序可以知道哪些引用引用的對象已經(jīng)被回收了。總結(jié):通過上面的流程分析,我們知道了并行和串行g(shù)c的區(qū)別在于: 并行g(shù)c會在mark第二階段將非gc線程喚醒;當(dāng)mark的第二階段完成之后,再次停止非gc線程;利用cardtable的信息再次進(jìn)行一個mark操作,此時的mark操作比第一個mark操作要快得多。并行g(shù)c會在sweep階段將非gc線程喚醒。串行g(shù)c會在垃圾回收開始就暫停所有非gc線程,知道垃圾回收結(jié)束。并行g(shù)c涉及到兩次的mark操作,消耗cpu時間。

ART虛擬機(jī)

在Android5.0中,ART取代了Dalvik虛擬機(jī)(安卓在4.4中發(fā)布了ART)。ART虛擬機(jī)直接執(zhí)行本地機(jī)器碼;而Dalvik虛擬機(jī)運(yùn)行的是DEX字節(jié)碼需要通過解釋器執(zhí)行。安卓運(yùn)行時從Dalvik虛擬機(jī)替換成ART虛擬機(jī),并不要求開發(fā)者重新將自己的應(yīng)用直接編譯成目標(biāo)機(jī)器碼,應(yīng)用程序仍然是一個包含dex字節(jié)碼的apk文件,這主要得益于AOT技術(shù),AOT(Ahead Of Time)是相對JIT(Just In Time)而言的;也就是在APK運(yùn)行之前,就對其包含的Dex字節(jié)碼進(jìn)行翻譯,得到對應(yīng)的本地機(jī)器指令,于是就可以在運(yùn)行時直接執(zhí)行了。ART應(yīng)用安裝的時候把dex中的字節(jié)碼將被編譯成本地機(jī)器碼,之后每次打開應(yīng)用,執(zhí)行的都是本地機(jī)器碼。去除了運(yùn)行時的解釋執(zhí)行,效率更高,啟動更快。ART運(yùn)行時內(nèi)部使用的Java堆的主要組成包括Image Space、Zygote Space、Allocation Space和Large Object Space四個Space,兩個Mod Union Table,一個Card Table,兩個Heap Bitmap,兩個Object Map(Live 和 Mark Object Map),以及三個Object Stack (Live、Mark、Allocation Stack)。具體結(jié)構(gòu)圖參考附錄。Image Space和Zygote Space之間,隔著一段用來映射system@framework@boot.art@classes.oat文件的內(nèi)存。system@framework@boot.art@classes.oat是一個OAT文件,它是由在系統(tǒng)啟動類路徑中的所有DEX文件翻譯得到的,Image Space映射的是一個system@framework@boot.art@classes.dex文件,這個文件保存的是在生成system@framework@boot.art@classes.oat這個OAT文件的時候需要預(yù)加載的類對象,這些需要預(yù)加載的類由/system/framework/framework.jar文件里面的preloaded-classes文件指定。以后只要系統(tǒng)啟動類路徑中的DEX文件不發(fā)生變化(即不發(fā)生更新升級),那么以后每次系統(tǒng)啟動只需要將文件system@framework@boot.art@classes.dex直接映射到內(nèi)存即可。由于system@framework@boot.art@classes.dex文件保存的是一些預(yù)先創(chuàng)建的對象,并且這些對象之間可能會互相引用,因此我們必須保證system@framework@boot.art@classes.dex文件每次加載到內(nèi)存的地址都是固定的。這個固定的地址保存在system@framework@boot.art@classes.dex文件開頭的一個Image Header中。此外,system@framework@boot.art@classes.dex文件也依賴于system@framework@boot.art@classes.oat文件,因此也會將后者固定加載到Image Space的末尾。Image Space是不能分配新對象的。Image Space和Zygote Space在Zygote進(jìn)程和應(yīng)用程序進(jìn)程之間進(jìn)行共享,而Allocation Space是每個進(jìn)程都獨(dú)立地?fù)碛幸环荨?h2>ART的運(yùn)行原理:在Android系統(tǒng)啟動過程中創(chuàng)建的Zygote進(jìn)程利用ART運(yùn)行時導(dǎo)出的Java虛擬機(jī)接口創(chuàng)建ART虛擬機(jī)。APK在安裝的時候,打包在里面的classes.dex文件會被工具dex2oat翻譯成本地機(jī)器指令,最終得到一個ELF格式的oat文件。APK運(yùn)行時,上述生成的oat文件會被加載到內(nèi)存中,并且ART虛擬機(jī)可以通過里面的oatdata和oatexec段找到任意一個類的方法對應(yīng)的本地機(jī)器指令來執(zhí)行。 oat文件中的oatdata包含用來生成本地機(jī)器指令的dex文件內(nèi)容oat文件中的oatexec包含有生成的本地機(jī)器指令。注意:這里將DEX文件中的類和方法稱之為DEX類和DEX方法,將OTA中的類和方法稱之為OTA類和OTA方法,ART運(yùn)行時將類和方法稱之為Class和ArtMethod。ART中一個已經(jīng)加載的Class對象包含了一系列的ArtField對象和ArtMethod對象,其中,ArtField對象用來描述成員變量信息,而ArtMethod用來描述成員函數(shù)信息。對于每一個ArtMethod對象,它都有一個解釋器入口點(diǎn)和一個本地機(jī)器指令入口點(diǎn)。

ART找到一個類和方法的流程:

在DEX文件中找到目標(biāo)DEX類的編號,并且以這個編號為索引,在OAT文件中找到對應(yīng)的OAT類。在DEX文件中找到目標(biāo)DEX方法的編號,并且以這個編號為索引,在上一步找到的OAT類中找到對應(yīng)的OAT方法。使用上一步找到的OAT方法的成員變量begin_和code_offset_,計算出該方法對應(yīng)的本地機(jī)器指令。上面的流程對應(yīng)給出了流程圖,具體內(nèi)容參考附錄。

ART運(yùn)行時對象的創(chuàng)建過程:

可以分配內(nèi)存的Space有三個:Zygote Space、Allocation Space和Large Object Space。不過,Zygote Space在還沒有劃分出Allocation Space之前,就在Zygote Space上分配,而當(dāng)Zygote Space劃分出Allocation Space之后,就只能在Allocation Space上分配。因此實(shí)際上應(yīng)用運(yùn)行的時候能夠分配內(nèi)存也就Allocation 和 Large Object Space兩個。而分配的對象究竟是存入上面的哪個Space呢?滿足如下三個條件的內(nèi)存,存入Large Object Space:1)Zygote Space已經(jīng)劃分除了Allocation Space,2)分配對象是原子類型數(shù)組,如int[] byte[] boolean[], 3)分配的內(nèi)存大小大于一定的門限值。對于分配對象時內(nèi)存不足的問題,是通過垃圾回收和在允許范圍內(nèi)增長堆大小解決的。由于垃圾回收會影響程序,因此ART運(yùn)行時采用力度從小到大的進(jìn)垃圾回收策略。一旦力度小的垃圾回收執(zhí)行過后能滿足分配要求,那就不需要進(jìn)行力度大的垃圾回收了。這跟dalvik虛擬機(jī)的對象分配策略也是類似的。

ART垃圾回收流程

并行GC流程圖如下: 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)InitializePhase執(zhí)行GC初始化階段。獲取用于訪問Java堆的鎖。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)MarkingPhase執(zhí)行GC并行標(biāo)記階段。釋放用于訪問Java堆的鎖。掛起所有的ART運(yùn)行時線程。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)HandleDirtyObjectsPhase處理在GC并行標(biāo)記階段被修改的對象。恢復(fù)第4步掛起的ART運(yùn)行時線程。重復(fù)第5到第7步,直到所有在GC并行階段被修改的對象都處理完成。獲取用于訪問Java堆的鎖。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)ReclaimPhase執(zhí)行GC回收階段。釋放用于訪問Java堆的鎖。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)FinishPhase執(zhí)行GC結(jié)束階段非并行GC流程圖如下: 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)InitializePhase執(zhí)行GC初始化階段。掛起所有的ART運(yùn)行時線程。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)MarkingPhase執(zhí)行GC標(biāo)記階段。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)ReclaimPhase執(zhí)行GC回收階段。恢復(fù)第2步掛起的ART運(yùn)行時線程。調(diào)用子類實(shí)現(xiàn)的成員函數(shù)FinishPhase執(zhí)行GC結(jié)束階段通過兩者的對比可以得出如下結(jié)論(與Dalvik大同小異): 非并行GC在垃圾回收的整個過程中暫停了所有非gc線程并行GC在一開始只是對堆進(jìn)行加鎖,對于那些暫時并不會在堆中分配的內(nèi)存的線程不起作用,它們依然可以運(yùn)行,但是會造成對象的引用發(fā)生變化,但是這段時間的引用發(fā)生的變化被記錄了下來。之后系統(tǒng)會停止所有線程,對上面記錄的數(shù)據(jù)進(jìn)行處理,然后喚起所有線程,系統(tǒng)進(jìn)入垃圾回收階段。

附錄:

Gygote堆預(yù)加載的類有:

該文件所指明的類就是通常gygote進(jìn)程在創(chuàng)建時預(yù)加載的類,基本上囊括Android開發(fā)中大部分使用到的類,如View、Activity以及java運(yùn)行時庫等都會進(jìn)行預(yù)加載。

Dalvik對應(yīng)的GC類型結(jié)構(gòu)體定義如下:

?
12345678910struct GcSpec {/* If true, only the application heap is threatened. */bool isPartial; /* If true, the trace is run concurrently with the mutator. */bool isConcurrent; /* Toggles for the soft reference clearing policy. */bool doPreserve; /* A name for this garbage collection mode. */constchar *reason; };

下圖就是根據(jù)Dalvik回收階段調(diào)用的dvmCollectGarbageInternal()函數(shù)所得到的流程圖

/ 圖.1、dvmCollectGarbageInternal函數(shù)針對并行和串行兩種gc的流程圖

下圖是ART的堆結(jié)構(gòu)圖

/圖.2、ART的堆結(jié)構(gòu)Mod Union Table對象 一個用來記錄在GC并行階段在Image Space上分配的對象對在Zygote Space和Allocation Space上分配的對象的引用。另一個用來記錄在GC并行階段在Zygote Space上分配的對象對在Allocation Space上分配的對象的引用。Allocation Stack:用來記錄上一次GC后分配的對象,用來實(shí)現(xiàn)類型為Sticky的Mark Sweep Collector。Live Stack:配合allocation_stack_一起使用,用來實(shí)現(xiàn)類型為Sticky的Mark Sweep Collector。Mark Stack:用來在GC過程中實(shí)現(xiàn)遞歸對象標(biāo)記 

ART找到一個類和方法的流程:

/圖.3、在OAT文件中查找類方法的本地機(jī)器指令的過程我們從左往右來看圖.3。首先是根據(jù)類簽名信息從包含在OAT文件里面的DEX文件中查找目標(biāo)Class的編號,然后再根據(jù)這個編號找到在OAT文件中找到對應(yīng)的OatClass。接下來再根據(jù)方法簽名從包含在OAT文件里面的DEX文件中查找目標(biāo)方法的編號,然后再根據(jù)這個編號在前面找到的OatClass中找到對應(yīng)的OatMethod。有了這個OatMethod之后,我們就根據(jù)它的成員變量begin_和code_offset_找到目標(biāo)類方法的本地機(jī)器指令了。其中,從DEX文件中根據(jù)簽名找到類和方法的編號要求對DEX文件進(jìn)行解析,這就需要利用Dalvik虛擬機(jī)的知識了。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 台湾省| 察哈| 乐亭县| 新绛县| 娱乐| 肇庆市| 乡城县| 宽城| 永昌县| 萨嘎县| 花垣县| 安义县| 鄄城县| 嘉义县| 右玉县| 蓬安县| 石楼县| 安福县| 武胜县| 吕梁市| 富顺县| 兰坪| 滦南县| 清河县| 杭锦旗| 康保县| 伊吾县| 正宁县| 大关县| 桂平市| 望城县| 温州市| 桐庐县| 大同市| 甘肃省| 如东县| 唐河县| 日土县| 青铜峡市| 农安县| 定南县|