版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Dalvik虛擬機(jī)垃圾收集(GC)過(guò)程分析前面我們分析了Dalvik虛擬機(jī)堆的創(chuàng)建過(guò)程,以及Java對(duì)象在堆上的分配過(guò)程。這些知識(shí)都是理解Dalvik虛擬機(jī)垃圾收集過(guò)程的基礎(chǔ)。垃圾收集是一個(gè)復(fù)雜的過(guò)程,它要將那些不再被引用的對(duì)象進(jìn)行回收。一方面要求Dalvik虛擬機(jī)能夠標(biāo)記出哪些對(duì)象是不再被引用的。另一方面要求Dalvik虛擬機(jī)盡快地回收內(nèi)存,避免應(yīng)用程序長(zhǎng)時(shí)間停頓。本文就將詳細(xì)分析Dalvik虛擬機(jī)是如何解決上述問(wèn)題完成垃圾收集過(guò)程的。Dalvik虛擬機(jī)使用Mark-Sweep算法來(lái)進(jìn)行垃圾收集。顧名思義,Mark-Sweep算法就是為Mark和Sweep兩個(gè)階段進(jìn)行垃圾回收。其中,Mark
2、階段從根集(Root Set)開始,遞歸地標(biāo)記出當(dāng)前所有被引用的對(duì)象,而Sweep階段負(fù)責(zé)回收那些沒(méi)有被引用的對(duì)象。在分析Dalvik虛擬機(jī)使用的Mark-Sweep算法之前,我們先來(lái)了解一下什么情況下會(huì)觸發(fā)GC。 Dallvik虛擬擬機(jī)在三種情情況下會(huì)觸發(fā)發(fā)四種類型的的GC。每一一種類型GCC使用一個(gè)GGcSpecc結(jié)構(gòu)體來(lái)描描述,它的定定義如下所示示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片struct GcSpeec /* Iff truee, onlly thee appllicatiion heeap iss threeateneed.
3、 */ bool isParrtial; /* Iff truee, thee tracce is run cconcurrrentlly witth thee mutaator. */ bool isConncurreent; /* Tooggless for the ssoft rrefereence ccleariing poolicy. */ bool doPreeservee; /* A name for tthis ggarbagge colllectiion moode. */ constt charr *reaason; ; 這個(gè)結(jié)構(gòu)構(gòu)體定義在文文件dalvvik/vmm/al
4、looc/Heaap.h中。 GcSppec結(jié)構(gòu)體體的各個(gè)成員員變量的含義義如下所示: isPaartiall: 為trrue時(shí),表表示僅僅回收收Activve堆的垃圾圾;為fallse時(shí),表表示同時(shí)回收收Activve堆和Zyygote堆堆的垃圾。 isCooncurrrent: 為truee時(shí),表示執(zhí)執(zhí)行并行GCC;為fallse時(shí),表表示執(zhí)行非并并行GC。 doPrreservve: 為ttrue時(shí),表表示在執(zhí)行GGC的過(guò)程中中,不回收軟軟引用引用的的對(duì)象;為ffalse時(shí)時(shí),表示在執(zhí)執(zhí)行GC的過(guò)過(guò)程中,回收收軟引用引用用的對(duì)象。 reasson: 一一個(gè)描述性的的字符串。 Davlli
5、k虛擬機(jī)機(jī)定義了四種種類的GC,如如下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片/* Not enouggh spaace foor an ordiinary Objeect too be aallocaated. */ extern constt GcSppec *GGC_FORR_MALLLOC; /* Autoomaticc GC ttriggeered bby excceedinng a hheap ooccupaancy tthreshhold. */ extern constt GcSppec *GGC_CONNCURREENT;
6、 /* Expllicit GC viia Runntime.gc(), VMRuuntimee.gc(), or SIGUSSR1. */ extern constt GcSppec *GGC_EXPPLICITT; /* Finaal atttempt to reeclaimm memoory beefore throwwing aan OOMM. */ extern constt GcSppec *GGC_BEFFORE_OOOM; 這四個(gè)全全局變量聲明明在文件daalvik/vm/allloc/HHeap.hh中。 它們的含含義如下所示示: GC_FFOR_MAALLOC: 表示是在在
7、堆上分配對(duì)對(duì)象時(shí)內(nèi)存不不足觸發(fā)的GGC。 GC_CCONCURRRENT: 表示是在在已分配內(nèi)存存達(dá)到一定量量之后觸發(fā)的的GC。 GC_EEXPLICCIT: 表表示是應(yīng)用程程序調(diào)用Syystem.gc、VMMRuntiime.gcc接口或者收收到SIGUUSR1信號(hào)號(hào)時(shí)觸發(fā)的GGC。 GC_BBEFOREE_OOM: 表示是在在準(zhǔn)備拋OOOM異常之前前進(jìn)行的最后后努力而觸發(fā)發(fā)的GC。 實(shí)際上,GGC_FORR_MALLLOC、GCC_CONCCURRENNT和GC_BEFORRE_OOMM三種類型的的GC都是在在分配對(duì)象的的過(guò)程觸發(fā)的的。 在前面一一文,我們提提到,Dallvik虛擬擬機(jī)在J
8、avva堆上分配配對(duì)象的時(shí)候候,在碰到分分配失敗的情情況,會(huì)嘗試試調(diào)用函數(shù)ggcForMMallocc進(jìn)行垃圾回回收。 函數(shù)gccForMaalloc的的實(shí)現(xiàn)如下所所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片static void gcForrMallooc(boool cleearSofftRefeerencees) connst GccSpec *specc = cllearSooftRefferencces ? GC_BEEFORE_OOM : GC_FFOR_MAALLOC; dvmmColleectGarrbageIInternnal
9、(sppec); 這個(gè)函數(shù)定定義在文件ddalvikk/vm/aalloc/Heap.cpp中。 參數(shù)cleearSOfftRefeerecess表示是否要要對(duì)軟引用引引用的對(duì)象進(jìn)進(jìn)行回收。如如果要對(duì)軟引引用引用的對(duì)對(duì)象進(jìn)行回收收,那么就表表明當(dāng)前內(nèi)存存是非常緊張張的了,因此此,這時(shí)候執(zhí)執(zhí)行的就是GGC_BEFFORE_OOOM類型的的GC。否則則的話,執(zhí)行行的就是GCC_FOR_MALLOOC類型的GGC。它們都都是通過(guò)調(diào)用用函數(shù)dvmmColleectGarrbageIInternnal來(lái)執(zhí)行行的。 在前面一文文,我們也提提到,當(dāng)Daalvik虛虛擬機(jī)成功地地在堆上分配配一個(gè)對(duì)象之之后,會(huì)
10、檢查查一下當(dāng)前分分配的內(nèi)存是是否超出一個(gè)個(gè)閥值,如下下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片void* ddvmHeaapSourrceAllloc(siize_t n) HeaapSourrce *hhs = ggHs; Heaap* heeap = hs2heeap(hss); if (heapp-byttesAlllocateed + nn hss-sofftLimiit) retuurn NUULL; voiid* pttr; if (gDvmm.lowMMemoryyMode) ptr = msppace_mmallocc(he
11、app-mspp, n); eelse ptr = msppace_ccallocc(heapp-mspp, 1, n); couuntAlllocatiion(heeap, pptr); if (heapp-byttesAlllocateed hheap-concuurrenttStarttBytess) dvmSSignallCond(&gHs-gcThhreadCCond); retturn pptr; 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/HeappSourcce.cppp中。 函數(shù)dvvmHeappSourcceAllooc成功地在在Activve堆上分配配到一個(gè)
12、對(duì)象象之后,就會(huì)會(huì)檢查Acttive堆當(dāng)當(dāng)前已經(jīng)分配配的內(nèi)存(hheap-bytessAlloccated)是是否大于預(yù)設(shè)設(shè)的閥值(hheap-concuurrenttStarttBytess)。如果大大于,那么就就會(huì)通過(guò)條件件變量gHss-gcTThreaddCond喚喚醒GC線程程進(jìn)行垃圾回回收。預(yù)設(shè)的的閥值(heeap-cconcurrrentSStartBBytes)是是一個(gè)比指定定的堆最小空空閑內(nèi)存小1128K的數(shù)數(shù)值。也就是是說(shuō),當(dāng)堆的的空閑內(nèi)不足足時(shí),就會(huì)觸觸發(fā)GC_CCONCURRRENT類類型的GC。 GC線程程是Dalvvik虛擬機(jī)機(jī)啟動(dòng)的過(guò)程程中創(chuàng)建的,它它的執(zhí)行體函函數(shù)
13、是gcDDaemonnThreaad,實(shí)現(xiàn)如如下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片static void *gcDaaemonTThreadd(voidd* argg) dvmmChanggeStattus(NUULL, TTHREADD_VMWAAIT); dvmmLockMMutex(&gHs-gcThhreadMMutex); whiile (ggHs-ggcThreeadShuutdownn != ttrue) booll trimm = faalse; if (gHs-gcThrreadTrrimNeeeded) int r
14、resultt = dvvmRelaativeCCondWaait(&ggHs-ggcThreeadConnd, &ggHs-ggcThreeadMuttex, HEEAP_TRRIM_IDDLE_TIIME_MSS, 0); if (rresultt = EETIMEDDOUT) /* Timmed ouut waiiting for aa GC rrequesst, scchedulle a hheap ttrim. */ ttrim = truee; ellse dvmWaaitConnd(&gHHs-gccThreaadCondd, &gHHs-gccThreaadMuteex); d
15、vmLLockHeeap(); if (!gDvmm.gcHeeap-ggcRunnning) dvmChhangeSStatuss(NULLL, THRREAD_RRUNNINNG); if (ttrim) ttrimHeeaps(); ggHs-ggcThreeadTriimNeedded = falsee; elsse ddvmColllectGGarbaggeInteernal(GC_COONCURRRENT); ggHs-ggcThreeadTriimNeedded = true; dvmChhangeSStatuss(NULLL, THRREAD_VVMWAITT); dvmUUn
16、lockkHeap(); dvmmChanggeStattus(NUULL, TTHREADD_RUNNNING); retturn NNULL; 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/HeappSourcce.cppp中。 GC線程程平時(shí)沒(méi)事的的時(shí)候,就在在條件變量ggHs-ggcThreeadConnd上進(jìn)行等等待HEAPP_TRIMM_IDLEE_TIMEE_MS毫秒秒(50000毫秒)。如如果在HEAAP_TRIIM_IDLLE_TIMME_MS毫毫秒內(nèi),都沒(méi)沒(méi)有得到執(zhí)行行GC的通知知,那么它就就調(diào)用函數(shù)ttrimHeeaps對(duì)JJava堆進(jìn)進(jìn)行裁剪,以以便可以將堆
17、堆上的一些沒(méi)沒(méi)有使用到的的內(nèi)存交還給給內(nèi)核。函數(shù)數(shù)trimHHeaps的的實(shí)現(xiàn)可以參參考前面一文文。否則的話話,就會(huì)調(diào)用用函數(shù)dvmmColleectGarrbageIInternnal進(jìn)行類類型為GC_CONCUURRENTT的GC。 注意,函函數(shù)gcDaaemonTThreadd在調(diào)用函數(shù)數(shù)dvmCoollecttGarbaageIntternall進(jìn)行類型為為GC_COONCURRRENT的GGC之前,會(huì)會(huì)先調(diào)用函數(shù)數(shù)dvmLoockHeaap來(lái)鎖定堆堆的。等到GGC執(zhí)行完畢畢,再調(diào)用函函數(shù)dvmUUnlockkHeap來(lái)來(lái)解除對(duì)堆的的鎖定。這與與函數(shù)gcFForMallloc調(diào)用用函數(shù)
18、dvmmColleectGarrbageIInternnal進(jìn)行類類型為GC_FOR_MMALLOCC和GC_CCONCURRRENT的的GC是一樣樣的。只不過(guò)過(guò),對(duì)堆進(jìn)行行鎖定和解鎖鎖的操作是在在調(diào)用堆棧上上的函數(shù)dvvmMallloc進(jìn)行的的,具體可以以參考前面一一文。 當(dāng)應(yīng)用程程序調(diào)用Syystem.gc、VMMRuntiime.gcc接口,或者者接收到SIIGUSR11信號(hào)時(shí),最最終會(huì)調(diào)用到到函數(shù)dvmmColleectGarrbage,它它的實(shí)現(xiàn)如下下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片void dvvmColllectGaa
19、rbagee() if (gDvmm.disaableExxpliciitGc) retuurn; dvmmLockHHeap(); dvmmWaitFForConncurreentGcTToCompplete(); dvmmColleectGarrbageIInternnal(GCC_EXPLLICIT); dvmmUnlocckHeapp(); 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/Allooc.cppp中。 如果Daavik虛擬擬機(jī)在啟動(dòng)的的時(shí)候,通過(guò)過(guò)-XX:+DisabbleExpplicittGC選項(xiàng)禁禁用了顯式GGC,那么函函數(shù)dvmCCollecctGarb
20、bage什么么也不做就返返回了。這意意味著Dallvik虛擬擬機(jī)可能會(huì)不不支持應(yīng)用程程序顯式的GGC請(qǐng)求。 一旦Dallvik虛擬擬機(jī)支持顯式式GC,那么么函數(shù)dvmmColleectGarrbage就就會(huì)先鎖定堆堆,并且等待待有可能正在在執(zhí)行的GCC_CONCCURRENNT類型的GGC完成之后后,再調(diào)用函函數(shù)dvmCCollecctGarbbageInnternaal進(jìn)行類型型為GC_EEXPLICCIT的GCC。 以上就是是三種情況下下會(huì)觸發(fā)四種種類型的GCC。有了這個(gè)個(gè)背景知識(shí)之之后 ,我們們接下來(lái)就開開始分析Daalvik虛虛擬機(jī)使用的的Mark-Sweepp算法,整個(gè)個(gè)過(guò)程如圖11
21、所示:圖1 Dalvvik虛擬機(jī)機(jī)垃圾收集過(guò)過(guò)程 Dalvvik虛擬機(jī)機(jī)支持非并行行和并行兩種種GC。在圖圖1中,左邊邊是非并行GGC的執(zhí)行過(guò)過(guò)程,而右邊邊是并行GCC的執(zhí)行過(guò)程程。它們的總總體流程是相相似的,主要要差別在于前前者在執(zhí)行的的過(guò)程中一直直是掛起非GGC線程的,而而后者是有條條件地掛起非非GC線程。 由前面的的分析可以知知道,無(wú)論是是并行GC,還還是非并行GGC,它們都都是通過(guò)函數(shù)數(shù)dvmCoollecttGarbaageIntternall來(lái)執(zhí)行的。函函數(shù)dvmCCollecctGarbbageInnternaal的實(shí)現(xiàn)如如下所示:cpp vview pplain copy 在C
22、ODEE上查看代碼碼片派生到我我的代碼片void dvvmColllectGaarbageeInterrnal(cconst GcSpeec* sppec) if (gcHeeap-ggcRunnning) retuurn; gcHHeap-gcRunnning = truue; dvmmSuspeendAlllThreaads(SUUSPENDD_FOR_GC); if (!dvmmHeapBBeginMMarkSttep(sppec-iisParttial) dvmAAbort(); dvmmHeapMMarkRoootSett(); if (specc-isCConcurrrent) d
23、vmCClearCCardTaable(); dvmUUnlockkHeap(); dvmRResumeeAllThhreadss(SUSPPEND_FFOR_GCC); dvmmHeapSScanMaarkedOObjectts(); if (specc-isCConcurrrent) dvmLLockHeeap(); dvmSSuspenndAllTThreadds(SUSSPEND_FOR_GGC); dvmHHeapReeMarkRRootSeet(); dvmHHeapReeScanMMarkeddObjeccts(); dvmmHeapPProcesssRefeerencees(&
24、gccHeap-softtReferrencess, speec-dooPreseerve = fallse, &gccHeap-weakkReferrencess, &gccHeap-finaalizerrReferrencess, &gccHeap-phanntomReeferennces); dvmmHeapSSweepSSystemmWeakss(); dvmmHeapSSourceeSwapBBitmapps(); if (specc-isCConcurrrent) dvmUUnlockkHeap(); dvmRResumeeAllThhreadss(SUSPPEND_FFOR_GC
25、C); dvmmHeapSSweepUUnmarkkedObjjects(spec-isPaartiall, speec-issConcuurrentt, &numOObjecttsFreeed, &nnumByttesFreeed); dvmmHeapFFinishhMarkSStep(); if (specc-isCConcurrrent) dvmLLockHeeap(); dvmmHeapSSourceeGrowFForUtiilizattion(); gcHHeap-gcRunnning = fallse; if (specc-isCConcurrrent) dvmBBroadccas
26、tCoond(&ggDvm.ggcHeappCond); if (!speec-issConcuurrentt) dvmRResumeeAllThhreadss(SUSPPEND_FFOR_GCC); dvmmEnqueeueCleearedRRefereences(&gDvmm.gcHeeap-ccleareedRefeerencees); 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/Heapp.cpp中中。 前面提到到,在調(diào)用函函數(shù)dvmCCollecctGarbbageInnternaal之前,堆堆是已經(jīng)被鎖鎖定了的,因因此這時(shí)候任任何需要堆上上分配對(duì)象的的線程都會(huì)被被掛起
27、。注意意,這不會(huì)影影響到那些不不需要在堆上上分配對(duì)象的的線程。 在圖1中中顯示的GCC流程中,除除了第一步的的Lock Heap和和最后一步的的Unlocck Heaap,都對(duì)應(yīng)應(yīng)于函數(shù)dvvmColllectGaarbageeInterrnal的實(shí)實(shí)現(xiàn),它的執(zhí)執(zhí)行邏輯如下下所示: 第1步到到第3步用于于并行和非并并行GC: 1. 調(diào)用函數(shù)ddvmSusspendAAllThrreads掛掛起所有的線線程,以免它它們干擾GCC。 2. 調(diào)用函數(shù)ddvmHeaapBegiinMarkkStep初初始化Marrk Staack,并且且設(shè)定好GCC范圍。關(guān)于于Mark Stackk的介紹,可可以參考
28、前面面一文。 3. 調(diào)用函數(shù)ddvmHeaapMarkkRootSSet標(biāo)記根根集對(duì)象。 第4到第第6步用于并并行GC: 4. 調(diào)用函數(shù)ddvmCleearCarrdTablle清理Caard Taable。關(guān)關(guān)于Cardd Tablle的介紹,可可以參考前面面一文。因?yàn)闉榻酉聛?lái)我們們將會(huì)喚醒第第1步掛起的的線程。并且且使用這個(gè)CCard TTable來(lái)來(lái)記錄那些在在GC過(guò)程中中被修改的對(duì)對(duì)象。 5. 調(diào)用函數(shù)ddvmUnllock解鎖鎖堆。這個(gè)是是針對(duì)調(diào)用函函數(shù)dvmCCollecctGarbbageInnternaal執(zhí)行GCC前的堆鎖定定操作。 6. 調(diào)用函數(shù)ddvmRessumeAll
29、lThreeads喚醒醒第1步掛起起的線程。 第7步用用于并行和非非并行GC: 7. 調(diào)用函數(shù)ddvmHeaapScannMarkeedObjeects從第第3步獲得的的根集對(duì)象開開始,歸遞標(biāo)標(biāo)記所有被根根集對(duì)象引用用的對(duì)象。 第8步到到第11步用用于并行GCC: 8. 調(diào)用函數(shù)ddvmLocckHeapp重新鎖定堆堆。這個(gè)是針針對(duì)前面第55步的操作。 9. 調(diào)用函數(shù)ddvmSusspendAAllThrreads重重新掛起所有有的線程。這這個(gè)是針對(duì)前前面第6步的的操作。 10. 調(diào)調(diào)用函數(shù)dvvmHeappReMarrkRoottSet更新新根集對(duì)象。因因?yàn)橛锌赡茉谠诘?步到第第6步的執(zhí)行行
30、過(guò)程中,有有線程創(chuàng)建了了新的根集對(duì)對(duì)象。 11. 調(diào)調(diào)用函數(shù)dvvmHeappReScaanMarkkedObjjects歸歸遞標(biāo)記那些些在第4步到到第6步的執(zhí)執(zhí)行過(guò)程中被被修改的對(duì)象象。這些對(duì)象象記錄在Caard Taable中。 第12步到到第14步用用于并行和非非并行GC: 12. 調(diào)調(diào)用函數(shù)dvvmHeappProceessRefferencces處理那那些被軟引用用(Softt Refeerencee)、弱引用用(Weakk Refeerencee)和影子引引用(Phaantom Referrence)引引用的對(duì)象,以以及重寫了ffinaliize方法的的對(duì)象。這些些對(duì)象都是需需要特
31、殊處理理的。 13. 調(diào)調(diào)用函數(shù)dvvmHeappSweeppSysteemWeakks回收系統(tǒng)統(tǒng)內(nèi)部使用的的那些被弱引引用引用的對(duì)對(duì)象。 14. 調(diào)調(diào)用函數(shù)dvvmHeappSourcceSwappBitmaaps交換LLive BBitmapp和Markk Bitmmap。執(zhí)行行了前面的113步之后,所所有還被引用用的對(duì)象在MMark BBitmapp中的bitt都被設(shè)置為為1。而Liive Biitmap記記錄的是當(dāng)前前GC前還被被引用著的對(duì)對(duì)象。通過(guò)交交換這兩個(gè)BBitmapp,就可以使使得當(dāng)前GCC完成之后,使使得Livee Bitmmap記錄的的是下次GCC前還被引用用著的對(duì)象。
32、第15步和和第16步用用于并行GCC: 15. 調(diào)調(diào)用函數(shù)dvvmUnloock解鎖堆堆。這個(gè)是針針對(duì)前面第88步的操作。 16. 調(diào)調(diào)用函數(shù)dvvmResuumeAlllThreaads喚醒第第9步掛起的的線程。 第17步和和第18步用用于并行和非非并行GC: 17. 調(diào)調(diào)用函數(shù)dvvmHeappSweeppUnmarrkedObbjectss回收那些沒(méi)沒(méi)有被引用的的對(duì)象。沒(méi)有有被引用的對(duì)對(duì)象就是那些些在執(zhí)行第114步之前,在在Live Bitmaap中的biit設(shè)置為11,但是在MMark BBitmapp中的bitt設(shè)置為0的的對(duì)象。 18. 調(diào)調(diào)用函數(shù)dvvmHeappFinisshM
33、arkkStep重重置Markk Bitmmap以及MMark SStack。這這個(gè)是針對(duì)前前面第2步的的操作。 第19步用用于并行GCC: 19. 調(diào)調(diào)用函數(shù)dvvmLockkHeap重重新鎖定堆。這這個(gè)是針對(duì)前前面第15步步的操作。 第20步用用于并行和非非并行GC: 20. 調(diào)調(diào)用函數(shù)dvvmHeappSourcceGrowwForUttilizaation根根據(jù)設(shè)置的堆堆目標(biāo)利用率率調(diào)整堆的大大小。 第21步用用于并行GCC: 21. 調(diào)調(diào)用函數(shù)dvvmBroaadcasttCond喚喚醒那些等待待GC執(zhí)行完完成再在堆上上分配對(duì)象的的線程。 第22步用用于非并行GGC: 22. 調(diào)調(diào)用
34、函數(shù)dvvmResuumeAlllThreaads喚醒第第1步掛起的的線程。 第23步用用到并行和非非并行GC: 23. 調(diào)調(diào)用函數(shù)dvvmEnquueueClleareddReferrencess將那些目標(biāo)標(biāo)對(duì)象已經(jīng)被被回收了的引引用對(duì)象增加加到相應(yīng)的JJava隊(duì)列列中去,以便便應(yīng)用程序可可以知道哪些些引用引用的的對(duì)象已經(jīng)被被回收了。 以上就是并并行和非并行行GC的執(zhí)行行總體流程,它它們的主要區(qū)區(qū)別在于,前前者在GC過(guò)過(guò)程中,有條條件地掛起和和喚醒非GCC線程,而后后者在執(zhí)行GGC的過(guò)程中中,一直都是是掛起非GCC線程的。并并行GC通過(guò)過(guò)有條件地掛掛起和喚醒非非GC線程,就就可以使得應(yīng)應(yīng)用程
35、序獲得得更好的響應(yīng)應(yīng)性。但是我我們也應(yīng)該看看到,并行GGC需要多執(zhí)執(zhí)行一次標(biāo)記記根集對(duì)象以以及遞歸標(biāo)記記那些在GCC過(guò)程被訪問(wèn)問(wèn)了的對(duì)象的的操作。也就就是說(shuō),并行行GC在使用用得應(yīng)用程序序獲得更好的的響應(yīng)性的同同時(shí),也需要要花費(fèi)更多的的CPU資源源。 為了更深入入地理解GCC的執(zhí)行過(guò)程程,接下來(lái)我我們?cè)僭敿?xì)分分析在上述的的23步中涉涉及到的重要要函數(shù)。 1. dvvmSusppendAlllThreeads 函數(shù)dvmmSuspeendAlllThreaads用來(lái)掛掛起Dalvvik虛擬機(jī)機(jī)中除當(dāng)前線線程之外的其其它線程,它它的實(shí)現(xiàn)如下下所示:cpp vview pplain copy 在CO
36、DEE上查看代碼碼片派生到我我的代碼片void dvvmSusppendAlllThreeads(SSuspenndCausse whyy) Thrread* self = dvmmThreaadSelff(); Thrread* threaad; locckThreeadSusspend(suspp-all, whyy); dvmmLockTThreaddList(self); locckThreeadSusspendCCount(); forr (thrread = gDvmm.threeadLisst; thhread != NUULL; tthreadd = thhread-nextt
37、) if (threaad = self) contiinue; /* ddebuggger evvents dontt susppend JJDWP tthreadd */ if (why = SUUSPENDD_FOR_DEBUGG | wwhy = SUSPPEND_FFOR_DEEBUG_EEVENT) & threaad-haandle = dvvmJdwppGetDeebugThhread(gDvm.jdwpSState) contiinue; dvmAAddToSSuspenndCounnts(thhread, 1, (wwhy = SUSPPEND_FFOR_DEEBUG |
38、whhy = SUSPEEND_FOOR_DEBBUG_EVVENT) ? 1 : 00); unllockThhreadSSuspenndCounnt(); forr (thrread = gDvmm.threeadLisst; thhread != NUULL; tthreadd = thhread-nextt) if (threaad = self) contiinue; /* ddebuggger evvents dontt susppend JJDWP tthreadd */ if (why = SUUSPENDD_FOR_DEBUGG | wwhy = SUSPPEND_FFOR_
39、DEEBUG_EEVENT) & threaad-haandle = dvvmJdwppGetDeebugThhread(gDvm.jdwpSState) contiinue; /* wwait ffor thhe othher thhread to seee thee pendding ssuspennd */ waittForThhreadSSuspennd(sellf, thhread); dvmmUnlocckThreeadLisst(); unllockThhreadSSuspennd(); 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/Threaad.cppp中。 在以下三三種情況下
40、,當(dāng)當(dāng)前線程需要要掛起其它線線程: 1. 執(zhí)執(zhí)行GC。 2. 調(diào)調(diào)試器請(qǐng)求。 3. 發(fā)發(fā)生調(diào)試事件件,如斷點(diǎn)命命中。 而且,上上述三種情況況有可能是同同時(shí)發(fā)生的。例例如,一個(gè)線線程在分配對(duì)對(duì)象的過(guò)程中中發(fā)生GC的的同時(shí),調(diào)試試器也剛好請(qǐng)請(qǐng)求掛起所有有線程。這時(shí)時(shí)候就需要保保證每一個(gè)掛掛起操作都是是順序執(zhí)行的的,即要對(duì)掛掛起線程的操操作進(jìn)行加鎖鎖。這是通過(guò)過(guò)調(diào)用函數(shù)函函數(shù)lockkThreaadSusppend來(lái)實(shí)實(shí)現(xiàn)的。 函數(shù)loockThrreadSuuspendd嘗試獲取ggDvm._threaadSusppendLoock鎖。如如果獲取失敗敗,就表明有有其它線程也也正在請(qǐng)求掛掛起Dalv
41、vik虛擬機(jī)機(jī)中的線程,包包括當(dāng)前線程程。每一個(gè)DDalvikk虛擬機(jī)線程程都有一個(gè)SSuspennd Couunt計(jì)數(shù),每每當(dāng)它們都掛掛起的時(shí)候,對(duì)對(duì)應(yīng)的Susspend Countt計(jì)數(shù)就會(huì)加加1,而當(dāng)被被喚醒時(shí),對(duì)對(duì)應(yīng)的Susspend Countt計(jì)數(shù)就會(huì)減減1。在獲取取gDvm._threeadSusspendLLock鎖失失敗的情況下下,當(dāng)前線程程按照一定的的時(shí)間間隔檢檢查自己的SSuspennd Couunt,直到到自己的Suuspendd Counnt等于0,并并且能成功獲獲取gDvmm._thrreadSuuspenddLock鎖鎖為止。這樣樣就可以保證證每一個(gè)掛起起Dalv
42、iik虛擬機(jī)線線程的請(qǐng)求都都能夠得到順順序執(zhí)行。 從函數(shù)llockThhreadSSuspennd返回之后后,就表明當(dāng)當(dāng)前線程可以以執(zhí)行掛起其其它線程的操操作了。它首首先要做的第第一件事情是是遍歷Dallvik虛擬擬機(jī)線程列表表,并且調(diào)用用函數(shù)dvmmAddTooSuspeendCouunts將列列表里面的每每一個(gè)線程對(duì)對(duì)應(yīng)的Susspend Countt都增加1,但但是除了當(dāng)前前線程之外。注注意,當(dāng)掛起起線程的請(qǐng)求求是調(diào)試器發(fā)發(fā)出或者是由由調(diào)試事件觸觸發(fā)的時(shí)候,DDalvikk虛擬機(jī)中的的JDWP線線程是不可以以掛起的,因因?yàn)镴DWPP線程掛起來(lái)來(lái)之后,就沒(méi)沒(méi)法調(diào)試了。在在這種情況下下,也不
43、能將將JDWP線線程對(duì)應(yīng)的SSuspennd Couunt都增加加1。 通過(guò)調(diào)用用函數(shù)dvmmJdwpGGetDebbugThrread可以以獲得JDWWP線程句柄柄,用這個(gè)句句柄和Dallvik虛擬擬機(jī)線程列表表中的線程句句柄相比,就就可以知道當(dāng)當(dāng)前遍歷的線線程是否是JJDWP線程程。同時(shí),通通過(guò)參數(shù)whhy可以知道道當(dāng)掛起線程程的請(qǐng)求是否否是由調(diào)試器器發(fā)出的或者者由調(diào)試事件件觸發(fā)的, 注意,在在增加被掛起起線程的Suuspendd Counnt計(jì)數(shù)之前前,必須要獲獲取gDvmm.threeadSusspendCCountLLock鎖。這這個(gè)鎖的獲取取和釋放可以以通過(guò)函數(shù)llockThhre
44、adSSuspenndCounnt和unllockThhreadSSuspenndCounnt完成。 將被掛起起線程的Suuspendd Counnt計(jì)數(shù)都增增加1之后,接接下來(lái)就是等等待被掛起線線程自愿將自自己掛起來(lái)了了。這是通過(guò)過(guò)函數(shù)waiitForTThreaddSuspeend來(lái)實(shí)現(xiàn)現(xiàn)。當(dāng)一個(gè)線線程自愿將自自己掛起來(lái)的的時(shí)候,會(huì)將將自己的狀態(tài)態(tài)設(shè)置為非運(yùn)運(yùn)行狀態(tài)(TTHREADD_RUNNNING),這這樣函數(shù)waaitForrThreaadSusppend通過(guò)過(guò)不斷地檢查查一個(gè)線程的的狀態(tài)是否處處于非運(yùn)行狀狀態(tài)就可以知知道它是否已已經(jīng)掛起來(lái)了了。 那么,一一個(gè)線程在什什么情況才會(huì)會(huì)自
45、愿將自己己掛起來(lái)呢?一個(gè)線程在在執(zhí)行的過(guò)程程中,會(huì)在合合適的時(shí)候檢檢查自己的SSuspennd Couunt計(jì)數(shù)。一一旦該計(jì)數(shù)值值不等于0,那那么它就知道道有線程請(qǐng)求求掛起自己,因因此它就會(huì)很很配合地將自自己的狀態(tài)設(shè)設(shè)置為非運(yùn)行行的,并且將將自己掛起來(lái)來(lái)。例如,當(dāng)當(dāng)一個(gè)線程通通過(guò)解釋器執(zhí)執(zhí)行代碼時(shí),就就會(huì)周期性地地檢查自己的的Suspeend Coount是否否等于0。這這里說(shuō)的周期期性,實(shí)際上上就是碰到IIF指令、GGOTO指令令、SWITTCH指令、RRETURNN指令和THHROW指令令等時(shí)。 2. dvvmHeappBeginnMarkSStep 函數(shù)dvmmHeapBBeginMMa
46、rkSttep用來(lái)初初始化堆的標(biāo)標(biāo)記范圍和MMark SStack,它它的實(shí)現(xiàn)如下下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片bool dvvmHeappBeginnMarkSStep(bbool iisParttial) GcMMarkCoontextt *ctxx = &ggDvm.ggcHeapp-marrkConttext; if (!creeateMaarkStaack(&cctx-sstack) retuurn faalse; ctxx-finnger = NULLL; ctxx-immmuneLiimit = (chaar*)d
47、vvmHeappSourcceGetIImmuneeLimitt(isPaartiall); retturn ttrue; 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/MarkkSweepp.cpp中中。 在標(biāo)記過(guò)過(guò)程中用到的的各種信息都都保存一個(gè)GGcMarkkConteext結(jié)構(gòu)體體描述的GCC標(biāo)記上下文文ctx中。其其中,ctxx-staack描述的的是Markk Stacck,ctxx-finnger描述述的是一個(gè)標(biāo)標(biāo)記指紋,在在遞歸標(biāo)記對(duì)對(duì)象時(shí)會(huì)用到到,ctx-immuuneLimmit用來(lái)限限定堆的標(biāo)記記范圍。 函數(shù)dvvmHeappBeginnMarkSStep調(diào)用
48、用另外一個(gè)函函數(shù)creaateMarrkStacck來(lái)初始化化Mark Stackk,它的實(shí)現(xiàn)現(xiàn)如下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片static bool creatteMarkkStackk(GcMaarkStaack *sstack) asssert(sstack != NUULL); sizze_t llengthh = dvvmHeappSourcceGetIIdealFFootprrint() * siizeof(Objecct*) / (sizzeof(OObjectt) + HHEAP_SSOURCEE_CHUNNK_
49、OVEERHEADD); maddvise(stackk-basse, leength, MADVV_NORMMAL); staack-ttop = stackk-basse; retturn ttrue; 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/MarkkSweepp.cpp中中。 函數(shù)crreateMMarkSttack根據(jù)據(jù)最壞情況來(lái)來(lái)設(shè)置Marrk Staack的長(zhǎng)度度,也就是用用當(dāng)前堆的大大小除以對(duì)象象占用的最小小內(nèi)存得到的的結(jié)果。當(dāng)前前堆的大小可可以通過(guò)函數(shù)數(shù)dvmHeeapSouurceGeetIdeaalFoottprintt來(lái)獲得。在在堆上分配的的對(duì)象,都是
50、是從Objeect類繼承承下來(lái)的,因因此,每一個(gè)個(gè)對(duì)象占用的的最小內(nèi)存是是sizeoof(Objject)。由由于在為對(duì)象象分配內(nèi)存時(shí)時(shí),還需要額額外的內(nèi)存來(lái)來(lái)保存管理信信息,例如實(shí)實(shí)際分配給對(duì)對(duì)象的內(nèi)存字字節(jié)數(shù)。這些些額外的管理理信息占用的的內(nèi)存字節(jié)數(shù)數(shù)通過(guò)宏HEEAP_SOOURCE_CHUNKK_OVERRHEAD來(lái)來(lái)描述。 由于Maark Sttack實(shí)際際上是一個(gè)OObjectt指針數(shù)組,因因此有了上面面的信息之后后,我們就可可以計(jì)算出MMark SStack的的長(zhǎng)度lenngth。MMark SStack使使用的內(nèi)存塊塊在Dalvvik虛擬機(jī)機(jī)啟動(dòng)的時(shí)候候就創(chuàng)建好的的,具體參考考前
51、面一文,起起始地址位于于stackk-basse中。由于于這塊內(nèi)存開開始的時(shí)候被被函數(shù)maddvice設(shè)設(shè)置為MADDV_DONNTNEEDD,因此這里里要將它重新新設(shè)置為MAADV_NOORMAL,以以便可以通知知內(nèi)核,這塊塊內(nèi)存要開始始使用了。 Markk Stacck的棧頂sstack-top指指向的是Maark Sttack內(nèi)存存塊的起始位位置,以后就就會(huì)從這個(gè)位位置開始由小小到大增長(zhǎng)。 回到函數(shù)數(shù)dvmHeeapBegginMarrkStepp中,ctxx-immmuneLiimit記錄錄的實(shí)際上是是堆的起始標(biāo)標(biāo)記位置。在在此位置之前前的對(duì)象,都都不會(huì)被GCC。這個(gè)位置置是通過(guò)函數(shù)數(shù)
52、dvmHeeapSouurceGeetImmuuneLimmit來(lái)確定定的,它的實(shí)實(shí)現(xiàn)如下所示示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片void *ddvmHeaapSourrceGettImmunneLimiit(boool isPPartiaal) if (isPaartiall) retuurn hss2heapp(gHs)-basse; eelse retuurn NUULL; 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/HeappSourcce.cppp中。 當(dāng)參數(shù)iisParttial等于于true時(shí)時(shí),函數(shù)dvvmH
53、eappSourcceGetIImmuneeLimitt返回的是AActivee堆的起始位位置,否則的的話就返回NNULL值。也也就是說(shuō),如如果當(dāng)前執(zhí)行行的GC只要要求回收部分分垃圾,那么么就只回收AActivee堆的垃圾,否否則的話,就就同時(shí)回收AActivee堆和Zyggote堆的的垃圾。 3. ddvmHeaapMarkkRootSSet 函數(shù)dvvmHeappMarkRRootSeet用來(lái)的標(biāo)標(biāo)記根集對(duì)象象,它的實(shí)現(xiàn)現(xiàn)如下所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片/* Markk the set oof rooot objjects.
54、 * * Thinngs wee needd to sscan: * - Syystem classses deefinedd by rroot cclasslloaderr * - Foor eacch thrread: * - Interrpreteed staack, ffrom ttop too currFramee * - Dallvik rregistters (args + loccal vaars) * - JNI llocal referrencess * - Autommatic VM loocal rrefereences (TracckedAllloc) * - Ass
55、occiatedd Threead/VMMThreaad objject * - ThreaadGrouups (ccould trackk & sttart wwith tthese insteead off workking * upwarrd froom Thrreads) * - Excepption curreently beingg throown, iif preesent * - JNNI gloobal rrefereences * - Innterneed strring ttable * - Prrimitiive cllassess * - Sppeciall obje
56、ects * - gDvm.outOffMemorryObj * - Obbjectss in ddebuggger obbject regisstry * * Dont neeed: * - Naative stackk (forr in-pprogreess sttuff iin thee VM) * - The TTrackeedAllooc stuuff waatchess all nativve VM referrencess. */ void dvvmHeappMarkRRootSeet() GcHHeap *gcHeaap = ggDvm.ggcHeapp; dvmmMarkII
57、mmuneeObjeccts(gccHeap-markkConteext.immmuneLLimit); dvmmVisittRootss(roottMarkOObjecttVisittor, &gcHeaap-maarkConntext); 這個(gè)函數(shù)數(shù)定義在文件件dalviik/vm/allocc/MarkkSweepp.cpp中中。 通過(guò)注釋釋我們可以看看到根集對(duì)象象都包含了哪哪些對(duì)象??偪偟膩?lái)說(shuō),就就是包含兩大大類對(duì)象。一一類是Dallvik虛擬擬機(jī)內(nèi)部使用用的全局對(duì)象象,另一類是是應(yīng)用程序正正在使用的對(duì)對(duì)象。前者會(huì)會(huì)維護(hù)在內(nèi)部部的一些數(shù)據(jù)據(jù)結(jié)構(gòu)中,例例如Hashh表,后者維維護(hù)在調(diào)用棧
58、棧中。對(duì)這些些根集對(duì)象進(jìn)進(jìn)行標(biāo)記都是是通過(guò)函數(shù)ddvmVissitRooots和回調(diào)調(diào)函數(shù)roootMarkkObjecctVisiitor進(jìn)行行的。 此外,我我們還需要將將不在堆回收收范圍內(nèi)的對(duì)對(duì)象也看作是是根集對(duì)象,以以便后面可以以使用統(tǒng)一的的方法來(lái)遍歷歷這兩類對(duì)象象所引用的其其它對(duì)象。標(biāo)標(biāo)記不在堆回回收范圍內(nèi)的的對(duì)象是通過(guò)過(guò)函數(shù)dvmmMarkIImmuneeObjeccts來(lái)實(shí)現(xiàn)現(xiàn)的,如下所所示:cpp vview pplain copy 在CODEE上查看代碼碼片派生到我我的代碼片void dvvmMarkkImmunneObjeects(cconst char *immuuneLi
59、mmit) forr (sizze_t ii = 1; i numHeeaps; +i) if (gHs-heapssi.bbase heaapsi.limiit heapssi.bbase - gHs-liveeBits.base); /* Coomputee the startting ooffsett in tthe liive annd marrk bitts. */ char *src = (chhar *)(gHs-liveeBits.bits + inddex); char *dst = (chhar *)(gHs-markkBits.bits + inddex); /* Coo
60、mputee the numbeer of bytess of tthe liive biitmap to coopy. */ size_t lenngth = HB_OOFFSETT_TO_BBYTE_IINDEX( ggHs-hheapsi.liimit - gHs-heappsi.base); /* Doo the copy. */ memcppy(dstt, srcc, lenngth); /* Maake suure maax poiints tto thee addrress oof thee highhest sset biit. */ if (ggHs-mmarkBiits.m
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 制作手冊(cè)合同模板
- 品牌宣傳活動(dòng)合同范例
- 工作牌合同范例
- 協(xié)會(huì)合作合同范例
- 京能集團(tuán)合同范例
- 德惠網(wǎng)紅民宿加盟合同模板
- 店家合作合同范例
- 商用光伏合同模板
- 供銷協(xié)議合同范例代銷
- 寧夏政府采購(gòu)合同模板
- 泵與泵站(水20)學(xué)習(xí)通課后章節(jié)答案期末考試題庫(kù)2023年
- 固定資產(chǎn)閑置處置方案
- 直流電動(dòng)機(jī)工作原理 名師獲獎(jiǎng)
- 防靜電安全知識(shí)員工培訓(xùn)
- 綜合實(shí)踐優(yōu)秀課件初二
- 礦熱爐(電爐)運(yùn)行有渣冶煉熔煉特性、電極插入深度解析與控制方法
- 妊娠晚期促子宮頸成熟與引產(chǎn)指南
- 基金委托募集合作協(xié)議
- GB/T 4942-2021旋轉(zhuǎn)電機(jī)整體結(jié)構(gòu)的防護(hù)等級(jí)(IP代碼)分級(jí)
- 醫(yī)院運(yùn)行與醫(yī)療業(yè)務(wù)指標(biāo)數(shù)據(jù)統(tǒng)計(jì)收集管理規(guī)定
- 風(fēng)險(xiǎn)因素識(shí)別與評(píng)價(jià)表(幕墻工程危險(xiǎn)源)
評(píng)論
0/150
提交評(píng)論