Dalvik虚拟机垃圾收集过程分析_第1页
Dalvik虚拟机垃圾收集过程分析_第2页
Dalvik虚拟机垃圾收集过程分析_第3页
Dalvik虚拟机垃圾收集过程分析_第4页
Dalvik虚拟机垃圾收集过程分析_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Dalviik虚拟机机垃圾收集集(GC)过过程分析前面我们分分析了Daalvikk虚拟机堆堆的创建过过程,以及及Javaa对象在堆堆上的分配配过程。这这些知识都都是理解DDalviik虚拟机机垃圾收集集过程的基基础。垃圾圾收集是一一个复杂的的过程,它它要将那些些不再被引引用的对象象进行回收收。一方面面要求Daalvikk虚拟机能能够标记出出哪些对象象是不再被被引用的。另一方面面要求Daalvikk虚拟机尽尽快地回收收内存,避避免应用程程序长时间间停顿。本本文就将详详细分析DDalviik虚拟机机是如何解解决上述问问题完成垃垃圾收集过过程的。Dalviik虚拟机机使用Maark-SSweepp算

2、法来进进行垃圾收收集。顾名名思义,MMark-Sweeep算法就就是为Maark和SSweepp两个阶段段进行垃圾圾回收。其其中,Maark阶段段从根集(RRoot Set)开开始,递归归地标记出出当前所有有被引用的的对象,而而Sweeep阶段负负责回收那那些没有被被引用的对对象。在分分析Dallvik虚虚拟机使用用的Marrk-Swweep算算法之前,我我们先来了了解一下什什么情况下下会触发GGC。 Dalvvik虚拟拟机在三种种情况下会会触发四种种类型的GGC。每一一种类型GGC使用一一个GcSSpec结结构体来描描述,它的的定义如下下所示:cpp vieew pllain copyy 在

3、COODE上查查看代码片片派生到我我的代码片片strucct GccSpecc /* If ttrue, onlly thhe apppliccatioon heeap iis thhreattenedd. */ boool issParttial; /* If ttrue, thee traace iis ruun cooncurrrenttly wwith the mutaator. */ boool issConccurreent; /* Togggles for the softt refferennce cclearring poliicy. */ boool dooPresserv

4、ee; /* A naame ffor tthis garbbage colllectiion mmode. */ connst cchar *reaason; ; 这这个结构体体定义在文文件dallvik/vm/aallocc/Heaap.h中中。 GGcSpeec结构体体的各个成成员变量的的含义如下下所示: iisParrtiall: 为ttrue时时,表示仅仅仅回收AActivve堆的垃垃圾;为ffalsee时,表示示同时回收收Actiive堆和和Zygoote堆的的垃圾。 iisConncurrrent: 为trrue时,表表示执行并并行GC;为fallse时,表表示执行非非并行GCC

5、。 ddoPreeservve: 为为truee时,表示示在执行GGC的过程程中,不回回收软引用用引用的对对象;为ffalsee时,表示示在执行GGC的过程程中,回收收软引用引引用的对象象。 rreasoon: 一一个描述性性的字符串串。 DDavliik虚拟机机定义了四四种类的GGC,如下下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片/* Noot ennoughh spaace ffor aan oordinnary Objject to bbe alllocaated. */ exterrn coonst GcSppec *GC_F

6、FOR_MMALLOOC; /* Auutomaatic GC ttrigggeredd by exceeedinng a heapp occcupanncy tthressholdd. */ exterrn coonst GcSppec *GC_CCONCUURRENNT; /* Exxpliccit GGC viia Ruuntimme.gcc(), VMRuuntimme.gcc(), or SSIGUSSR1. */ exterrn coonst GcSppec *GC_EEXPLIICIT; /* Fiinal atteempt to rreclaaim mmemorry beefo

7、ree thrrowinng ann OOMM. */ exterrn coonst GcSppec *GC_BBEFORRE_OOOM; 这这四个全局局变量声明明在文件ddalviik/vmm/allloc/HHeap.h中。 它它们的含义义如下所示示: GGC_FOOR_MAALLOCC: 表示示是在堆上上分配对象象时内存不不足触发的的GC。 GGC_COONCURRRENTT: 表示示是在已分分配内存达达到一定量量之后触发发的GC。 GGC_EXXPLICCIT: 表示是应应用程序调调用Sysstem.gc、VVMRunntimee.gc接接口或者收收到SIGGUSR11信号时触触发的G

8、CC。 GGC_BEEFOREE_OOMM: 表示示是在准备备抛OOMM异常之前前进行的最最后努力而而触发的GGC。 实实际上,GGC_FOOR_MAALLOCC、GC_CONCCURREENT和GGC_BEEFOREE_OOMM三种类型型的GC都都是在分配配对象的过过程触发的的。 在在前面一文文,我们提提到,Daalvikk虚拟机在在Javaa堆上分配配对象的时时候,在碰碰到分配失失败的情况况,会尝试试调用函数数gcFoorMallloc进进行垃圾回回收。 函函数gcFForMaallocc的实现如如下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我

9、的代码片片statiic vooid ggcForrMallloc(bbool cleaarSofftRefferennces) cconstt GcSSpec *speec = cleaarSofftRefferennces ? GCC_BEFFORE_OOM : GCC_FORR_MALLLOC; ddvmCoollecctGarrbageeInteernall(speec); 这个个函数定义义在文件ddalviik/vmm/allloc/HHeap.cpp中中。 参数数cleaarSOfftRefferecces表示示是否要对对软引用引引用的对象象进行回收收。如果要要对软引用用引用的对对

10、象进行回回收,那么么就表明当当前内存是是非常紧张张的了,因因此,这时时候执行的的就是GCC_BEFFORE_OOM类类型的GCC。否则的的话,执行行的就是GGC_FOOR_MAALLOCC类型的GGC。它们们都是通过过调用函数数dvmCColleectGaarbaggeIntternaal来执行行的。 在前前面一文,我我们也提到到,当Daalvikk虚拟机成成功地在堆堆上分配一一个对象之之后,会检检查一下当当前分配的的内存是否否超出一个个阀值,如如下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片void* dvmmHeappSourrceA

11、llloc(sizee_t nn) HHeapSSourcce *hhs = gHs; HHeap* heaap = hs2hheap(hs); iif (hheap-byttesAlllocaated + n hss-sooftLiimit) rreturrn NUULL; vvoid* ptrr; iif (ggDvm.lowMMemorryModde) pptr = msppace_mallloc(hheap-mspp, n); elsse pptr = msppace_callloc(hheap-mspp, 1, n); ccounttAlloocatiion(hheap, ptrr)

12、; iif (hheap-byttesAlllocaated heeap-conccurreentSttartBBytess) ddvmSiignallCondd(&gHHs-ggcThrreadCCond); rreturrn pttr; 这这个函数定定义在文件件dalvvik/vvm/allloc/HeappSourrce.ccpp中。 函函数dvmmHeappSourrceAllloc成成功地在AActivve堆上分分配到一个个对象之后后,就会检检查Acttive堆堆当前已经经分配的内内存(heeap-byteesAlllocatted)是是否大于预预设的阀值值(heaap-cconcu

13、urrenntStaartByytes)。如果大于于,那么就就会通过条条件变量ggHs-gcThhreaddCondd唤醒GCC线程进行行垃圾回收收。预设的的阀值(hheap-conncurrrentSStarttBytees)是一一个比指定定的堆最小小空闲内存存小1288K的数值值。也就是是说,当堆堆的空闲内内不足时,就就会触发GGC_COONCURRRENTT类型的GGC。 GGC线程是是Dalvvik虚拟拟机启动的的过程中创创建的,它它的执行体体函数是ggcDaeemonTThreaad,实现现如下所示示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我

14、我的代码片片statiic vooid *gcDaaemonnThreead(vvoid* argg) ddvmChhangeeStattus(NNULL, THRREAD_VMWAAIT); ddvmLoockMuutex(&gHss-gccThreeadMuutex); wwhilee (gHHs-ggcThrreadSShutddown != ttrue) bbool trimm = ffalsee; iif (ggHs-gcThhreaddTrimmNeedded) iint rresullt = dvmRRelattiveCCondWWait(&gHss-gccThreeadCoon

15、d, &gHss-gccThreeadMuutex, HHEAP_TRIMM_IDLLE_TIIME_MMS, 00); iif (rresullt = ETIIMEDOOUT) /* Tiimed out waitting for a GCC reqquestt, sccheduule aa heaap trrim. */ ttrim = trrue; elsse ddvmWaaitCoond(&gHs-gcTThreaadConnd, &gHs-gcTThreaadMuttex); ddvmLoockHeeap(); iif (!gDvmm.gcHHeap-gcRRunniing) ddv

16、mChhangeeStattus(NNULL, THRREAD_RUNNNING); iif (ttrim) ttrimHHeapss(); ggHs-gcThhreaddTrimmNeedded = fallse; elsse ddvmCoollecctGarrbageeInteernall(GC_CONCCURREENT); ggHs-gcThhreaddTrimmNeedded = truue; ddvmChhangeeStattus(NNULL, THRREAD_VMWAAIT); ddvmUnnlockkHeapp(); ddvmChhangeeStattus(NNULL, THRR

17、EAD_RUNNNING); rreturrn NUULL; 这这个函数定定义在文件件dalvvik/vvm/allloc/HeappSourrce.ccpp中。 GGC线程平平时没事的的时候,就就在条件变变量gHss-gccThreeadCoond上进进行等待HHEAP_TRIMM_IDLLE_TIIME_MMS毫秒(55000毫毫秒)。如如果在HEEAP_TTRIM_IDLEE_TIMME_MSS毫秒内,都都没有得到到执行GCC的通知,那那么它就调调用函数ttrimHHeapss对Javva堆进行行裁剪,以以便可以将将堆上的一一些没有使使用到的内内存交还给给内核。函函数triimHeaap

18、s的实实现可以参参考前面一一文。否则则的话,就就会调用函函数dvmmColllectGGarbaageInnternnal进行行类型为GGC_COONCURRRENTT的GC。 注注意,函数数gcDaaemonnThreead在调调用函数ddvmCoollecctGarrbageeInteernall进行类型型为GC_CONCCURREENT的GGC之前,会会先调用函函数dvmmLockkHeapp来锁定堆堆的。等到到GC执行行完毕,再再调用函数数dvmUUnlocckHeaap来解除除对堆的锁锁定。这与与函数gccForMMallooc调用函函数dvmmColllectGGarbaageIn

19、nternnal进行行类型为GGC_FOOR_MAALLOCC和GC_CONCCURREENT的GGC是一样样的。只不不过,对堆堆进行锁定定和解锁的的操作是在在调用堆栈栈上的函数数dvmMMallooc进行的的,具体可可以参考前前面一文。 当当应用程序序调用Syystemm.gc、VMRuuntimme.gcc接口,或或者接收到到SIGUUSR1信信号时,最最终会调用用到函数ddvmCoollecctGarrbagee,它的实实现如下所所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片void dvmCColleectGaarbagge() i

20、if (ggDvm.disaableEExpliicitGGc) rreturrn; ddvmLoockHeeap(); ddvmWaaitFoorConncurrrentGGcToCCompllete(); ddvmCoollecctGarrbageeInteernall(GC_EXPLLICITT); ddvmUnnlockkHeapp(); 这这个函数定定义在文件件dalvvik/vvm/allloc/Allooc.cppp中。 如如果Davvik虚拟拟机在启动动的时候,通通过-XXX:+DiisablleExppliciitGC选选项禁用了了显式GCC,那么函函数dvmmColllec

21、tGGarbaage什么么也不做就就返回了。这意味着着Dalvvik虚拟拟机可能会会不支持应应用程序显显式的GCC请求。 一旦旦Dalvvik虚拟拟机支持显显式GC,那那么函数ddvmCoollecctGarrbagee就会先锁锁定堆,并并且等待有有可能正在在执行的GGC_COONCURRRENTT类型的GGC完成之之后,再调调用函数ddvmCoollecctGarrbageeInteernall进行类型型为GC_EXPLLICITT的GC。 以以上就是三三种情况下下会触发四四种类型的的GC。有有了这个背背景知识之之后 ,我我们接下来来就开始分分析Dallvik虚虚拟机使用用的Marrk-Sw

22、weep算算法,整个个过程如图图1所示:图1 Daalvikk虚拟机垃垃圾收集过过程 DDalviik虚拟机机支持非并并行和并行行两种GCC。在图11中,左边边是非并行行GC的执执行过程,而而右边是并并行GC的的执行过程程。它们的的总体流程程是相似的的,主要差差别在于前前者在执行行的过程中中一直是挂挂起非GCC线程的,而而后者是有有条件地挂挂起非GCC线程。 由由前面的分分析可以知知道,无论论是并行GGC,还是是非并行GGC,它们们都是通过过函数dvvmColllecttGarbbageIInterrnal来来执行的。函数dvvmColllecttGarbbageIInterrnal的的实现如

23、下下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片void dvmCColleectGaarbaggeIntternaal(coonst GcSppec* specc) iif (ggcHeaap-ggcRunnningg) rreturrn; ggcHeaap-ggcRunnningg = ttrue; ddvmSuuspenndAlllThreeads(SUSPPEND_FOR_GC); iif (!dvmHHeapBBeginnMarkkStepp(speec-iisParrtiall) ddvmAbbort(); ddvmHeeap

24、MaarkRoootSeet(); iif (sspec-isCConcuurrennt) ddvmCllearCCardTTablee(); ddvmUnnlockkHeapp(); ddvmReesumeeAllTThreaads(SSUSPEEND_FFOR_GGC); ddvmHeeapSccanMaarkeddObjeects(); iif (sspec-isCConcuurrennt) ddvmLoockHeeap(); ddvmSuuspenndAlllThreeads(SUSPPEND_FOR_GC); ddvmHeeapReeMarkkRoottSet(); ddvmHeea

25、pReeScannMarkkedObbjectts(); ddvmHeeapPrrocesssRefferennces(&gcHHeap-sofftRefferennces, specc-dooPresservee = falsse, &gcHHeap-weaakRefferennces, &gcHHeap-finnalizzerReefereencess, &gcHHeap-phaantommRefeerencces); ddvmHeeapSwweepSSysteemWeaaks(); ddvmHeeapSoourceeSwappBitmmaps(); iif (sspec-isCConcu

26、urrennt) ddvmUnnlockkHeapp(); ddvmReesumeeAllTThreaads(SSUSPEEND_FFOR_GGC); ddvmHeeapSwweepUUnmarrkedOObjeccts(sspec-isPPartiial, specc-issConccurreent, &numOObjecctsFrreed, &nuumByttesFrreed); ddvmHeeapFiinishhMarkkStepp(); iif (sspec-isCConcuurrennt) ddvmLoockHeeap(); ddvmHeeapSoourceeGrowwForUUti

27、liizatiion(); ggcHeaap-ggcRunnningg = ffalsee; iif (sspec-isCConcuurrennt) ddvmBrroadccastCCond(&gDvvm.gccHeappCondd); iif (!specc-issConccurreent) ddvmReesumeeAllTThreaads(SSUSPEEND_FFOR_GGC); ddvmEnnqueuueCleeareddRefeerencces(&gDvmm.gcHHeap-cleeareddRefeerencces); 这这个函数定定义在文件件dalvvik/vvm/allloc/H

28、eapp.cppp中。 前前面提到,在在调用函数数dvmCColleectGaarbaggeIntternaal之前,堆堆是已经被被锁定了的的,因此这这时候任何何需要堆上上分配对象象的线程都都会被挂起起。注意,这这不会影响响到那些不不需要在堆堆上分配对对象的线程程。 在在图1中显显示的GCC流程中,除除了第一步步的Locck Heeap和最最后一步的的Unloock HHeap,都都对应于函函数dvmmColllectGGarbaageInnternnal的实实现,它的的执行逻辑辑如下所示示: 第第1步到第第3步用于于并行和非非并行GCC: 11. 调调用函数ddvmSuuspenndAlll

29、Threeads挂挂起所有的的线程,以以免它们干干扰GC。 22. 调调用函数ddvmHeeapBeeginMMarkSStep初初始化Maark SStackk,并且设设定好GCC范围。关关于Marrk Sttack的的介绍,可可以参考前前面一文。 33. 调调用函数ddvmHeeapMaarkRoootSeet标记根根集对象。 第第4到第66步用于并并行GC: 44. 调调用函数ddvmCllearCCardTTablee清理Caard TTablee。关于CCard Tablle的介绍绍,可以参参考前面一一文。因为为接下来我我们将会唤唤醒第1步步挂起的线线程。并且且使用这个个Cardd

30、Tabble来记记录那些在在GC过程程中被修改改的对象。 55. 调调用函数ddvmUnnlockk解锁堆。这个是针针对调用函函数dvmmColllectGGarbaageInnternnal执行行GC前的的堆锁定操操作。 66. 调调用函数ddvmReesumeeAllTThreaads唤醒醒第1步挂挂起的线程程。 第第7步用于于并行和非非并行GCC: 77. 调调用函数ddvmHeeapSccanMaarkeddObjeects从从第3步获获得的根集集对象开始始,归递标标记所有被被根集对象象引用的对对象。 第第8步到第第11步用用于并行GGC: 88. 调调用函数ddvmLoockHeea

31、p重新新锁定堆。这个是针针对前面第第5步的操操作。 99. 调调用函数ddvmSuuspenndAlllThreeads重重新挂起所所有的线程程。这个是是针对前面面第6步的的操作。 100. 调用用函数dvvmHeaapReMMarkRRootSSet更新新根集对象象。因为有有可能在第第4步到第第6步的执执行过程中中,有线程程创建了新新的根集对对象。 111. 调用用函数dvvmHeaapReSScanMMarkeedObjjectss归递标记记那些在第第4步到第第6步的执执行过程中中被修改的的对象。这这些对象记记录在Caard TTablee中。 第112步到第第14步用用于并行和和非并行G

32、GC: 122. 调用用函数dvvmHeaapProocesssRefeerencces处理理那些被软软引用(SSoft Refeerencce)、弱弱引用(WWeak Refeerencce)和影影子引用(PPhanttom RReferrencee)引用的的对象,以以及重写了了finaalizee方法的对对象。这些些对象都是是需要特殊殊处理的。 133. 调用用函数dvvmHeaapSweeepSyystemmWeakks回收系系统内部使使用的那些些被弱引用用引用的对对象。 144. 调用用函数dvvmHeaapSouurceSSwapBBitmaaps交换换Livee Bittmap和和

33、Markk Bittmap。执行了前前面的133步之后,所所有还被引引用的对象象在Marrk Biitmapp中的biit都被设设置为1。而Livve Biitmapp记录的是是当前GCC前还被引引用着的对对象。通过过交换这两两个Bittmap,就就可以使得得当前GCC完成之后后,使得LLive Bitmmap记录录的是下次次GC前还还被引用着着的对象。 第115步和第第16步用用于并行GGC: 155. 调用用函数dvvmUnllock解解锁堆。这这个是针对对前面第88步的操作作。 166. 调用用函数dvvmRessumeAAllThhreadds唤醒第第9步挂起起的线程。 第117步和第

34、第18步用用于并行和和非并行GGC: 177. 调用用函数dvvmHeaapSweeepUnnmarkkedObbjectts回收那那些没有被被引用的对对象。没有有被引用的的对象就是是那些在执执行第144步之前,在在Livee Bittmap中中的bitt设置为11,但是在在Markk Bittmap中中的bitt设置为00的对象。 188. 调用用函数dvvmHeaapFinnishMMarkSStep重重置Marrk Biitmapp以及Maark SStackk。这个是是针对前面面第2步的的操作。 第119步用于于并行GCC: 199. 调用用函数dvvmLocckHeaap重新锁锁定堆

35、。这这个是针对对前面第115步的操操作。 第220步用于于并行和非非并行GCC: 200. 调用用函数dvvmHeaapSouurceGGrowFForUttilizzatioon根据设设置的堆目目标利用率率调整堆的的大小。 第221步用于于并行GCC: 211. 调用用函数dvvmBrooadcaastCoond唤醒醒那些等待待GC执行行完成再在在堆上分配配对象的线线程。 第222步用于于非并行GGC: 222. 调用用函数dvvmRessumeAAllThhreadds唤醒第第1步挂起起的线程。 第223步用到到并行和非非并行GCC: 233. 调用用函数dvvmEnqqueueeClea

36、aredRReferrencees将那些些目标对象象已经被回回收了的引引用对象增增加到相应应的Javva队列中中去,以便便应用程序序可以知道道哪些引用用引用的对对象已经被被回收了。 以上上就是并行行和非并行行GC的执执行总体流流程,它们们的主要区区别在于,前前者在GCC过程中,有有条件地挂挂起和唤醒醒非GC线线程,而后后者在执行行GC的过过程中,一一直都是挂挂起非GCC线程的。并行GCC通过有条条件地挂起起和唤醒非非GC线程程,就可以以使得应用用程序获得得更好的响响应性。但但是我们也也应该看到到,并行GGC需要多多执行一次次标记根集集对象以及及递归标记记那些在GGC过程被被访问了的的对象的操操

37、作。也就就是说,并并行GC在在使用得应应用程序获获得更好的的响应性的的同时,也也需要花费费更多的CCPU资源源。 为了了更深入地地理解GCC的执行过过程,接下下来我们再再详细分析析在上述的的23步中中涉及到的的重要函数数。 1. dvmmSusppendAAllThhreadds 函数数dvmSSuspeendAlllThrreadss用来挂起起Dalvvik虚拟拟机中除当当前线程之之外的其它它线程,它它的实现如如下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片void dvmSSuspeendAlllThrreadss(Susspendd

38、Causse whhy) TThreaad* sself = dvvmThrreadSSelf(); TThreaad* tthreaad; llockTThreaadSusspendd(suusp-aall, whyy); ddvmLoockThhreaddListt(sellf); llockTThreaadSusspenddCounnt(); ffor (threead = gDvvm.thhreaddListt; thhreadd != NULLL; thhreadd = tthreaad-nnext) iif (tthreaad = sellf) ccontiinue; /* dee

39、buggger eeventts doont susppend JDWPP thrread */ iif (why = SSUSPEEND_FFOR_DDEBUGG | why = SSUSPEEND_FFOR_DDEBUGG_EVEENT) & tthreaad-hhandlle = dvmmJdwppGetDDebuggThreead(ggDvm.jdwppStatte) ccontiinue; ddvmAdddToSSuspeendCoountss(thrread, 1, (whhy = SUSSPENDD_FORR_DEBBUG | whyy = SUSPPEND_FOR_DEBUUG

40、_EVVENT) ? 11 : 00); uunlocckThrreadSSuspeendCoount(); ffor (threead = gDvvm.thhreaddListt; thhreadd != NULLL; thhreadd = tthreaad-nnext) iif (tthreaad = sellf) ccontiinue; /* deebuggger eeventts doont susppend JDWPP thrread */ iif (why = SSUSPEEND_FFOR_DDEBUGG | why = SSUSPEEND_FFOR_DDEBUGG_EVEENT)

41、 & tthreaad-hhandlle = dvmmJdwppGetDDebuggThreead(ggDvm.jdwppStatte) ccontiinue; /* waait ffor tthe ootherr thrread to ssee tthe ppendiing ssuspeend */ wwaitFForThhreaddSusppend(selff, thhreadd); ddvmUnnlockkThreeadLiist(); uunlocckThrreadSSuspeend(); 这这个函数定定义在文件件dalvvik/vvm/Thhreadd.cppp中。 在在以下三种种情

42、况下,当当前线程需需要挂起其其它线程: 11. 执行行GC。 22. 调试试器请求。 33. 发生生调试事件件,如断点点命中。 而而且,上述述三种情况况有可能是是同时发生生的。例如如,一个线线程在分配配对象的过过程中发生生GC的同同时,调试试器也刚好好请求挂起起所有线程程。这时候候就需要保保证每一个个挂起操作作都是顺序序执行的,即即要对挂起起线程的操操作进行加加锁。这是是通过调用用函数函数数lockkThreeadSuuspennd来实现现的。 函函数locckThrreadSSuspeend尝试试获取gDDvm._threeadSuuspenndLocck锁。如如果获取失失败,就表表明有其它

43、它线程也正正在请求挂挂起Dallvik虚虚拟机中的的线程,包包括当前线线程。每一一个Dallvik虚虚拟机线程程都有一个个Susppend Counnt计数,每每当它们都都挂起的时时候,对应应的Susspendd Couunt计数数就会加11,而当被被唤醒时,对对应的Suuspennd Coount计计数就会减减1。在获获取gDvvm._tthreaadSusspenddLockk锁失败的的情况下,当当前线程按按照一定的的时间间隔隔检查自己己的Susspendd Couunt,直直到自己的的Susppend Counnt等于00,并且能能成功获取取gDvmm._thhreaddSusppend

44、LLock锁锁为止。这这样就可以以保证每一一个挂起DDalviik虚拟机机线程的请请求都能够够得到顺序序执行。 从从函数loockThhreaddSusppend返返回之后,就就表明当前前线程可以以执行挂起起其它线程程的操作了了。它首先先要做的第第一件事情情是遍历DDalviik虚拟机机线程列表表,并且调调用函数ddvmAdddToSSuspeendCoountss将列表里里面的每一一个线程对对应的Suuspennd Coount都都增加1,但但是除了当当前线程之之外。注意意,当挂起起线程的请请求是调试试器发出或或者是由调调试事件触触发的时候候,Dallvik虚虚拟机中的的JDWPP线程是不不

45、可以挂起起的,因为为JDWPP线程挂起起来之后,就就没法调试试了。在这这种情况下下,也不能能将JDWWP线程对对应的Suuspennd Coount都都增加1。 通通过调用函函数dvmmJdwppGetDDebuggThreead可以以获得JDDWP线程程句柄,用用这个句柄柄和Dallvik虚虚拟机线程程列表中的的线程句柄柄相比,就就可以知道道当前遍历历的线程是是否是JDDWP线程程。同时,通通过参数wwhy可以以知道当挂挂起线程的的请求是否否是由调试试器发出的的或者由调调试事件触触发的, 注注意,在增增加被挂起起线程的SSuspeend CCountt计数之前前,必须要要获取gDDvm.tt

46、hreaadSusspenddCounntLocck锁。这这个锁的获获取和释放放可以通过过函数loockThhreaddSusppendCCountt和unllockTThreaadSusspenddCounnt完成。 将将被挂起线线程的Suuspennd Coount计计数都增加加1之后,接接下来就是是等待被挂挂起线程自自愿将自己己挂起来了了。这是通通过函数wwaitFForThhreaddSusppend来来实现。当当一个线程程自愿将自自己挂起来来的时候,会会将自己的的状态设置置为非运行行状态(TTHREAAD_RUUNNINNG),这这样函数wwaitFForThhreaddSusppe

47、nd通通过不断地地检查一个个线程的状状态是否处处于非运行行状态就可可以知道它它是否已经经挂起来了了。 那那么,一个个线程在什什么情况才才会自愿将将自己挂起起来呢?一一个线程在在执行的过过程中,会会在合适的的时候检查查自己的SSuspeend CCountt计数。一一旦该计数数值不等于于0,那么么它就知道道有线程请请求挂起自自己,因此此它就会很很配合地将将自己的状状态设置为为非运行的的,并且将将自己挂起起来。例如如,当一个个线程通过过解释器执执行代码时时,就会周周期性地检检查自己的的Susppend Counnt是否等等于0。这这里说的周周期性,实实际上就是是碰到IFF指令、GGOTO指指令、S

48、WWITCHH指令、RRETURRN指令和和THROOW指令等等时。 2. dvmmHeappBegiinMarrkSteep 函数数dvmHHeapBBeginnMarkkStepp用来初始始化堆的标标记范围和和Markk Staack,它它的实现如如下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片bool dvmHHeapBBeginnMarkkStepp(boool issParttial) GGcMarrkConntextt *cttx = &gDvvm.gccHeapp-maarkCoontexxt; iif (!creaateM

49、aarkSttack(&ctxx-sttack) rreturrn faalse; cctx-fingger = NULLL; cctx-immuuneLiimit = (cchar*)dvmmHeappSourrceGeetImmmuneLLimitt(isPPartiial); rreturrn trrue; 这这个函数定定义在文件件dalvvik/vvm/allloc/MarkkSweeep.cppp中。 在在标记过程程中用到的的各种信息息都保存一一个GcMMarkCConteext结构构体描述的的GC标记记上下文cctx中。其中,cctx-stacck描述的的是Marrk Sttack

50、,cctx-fingger描述述的是一个个标记指纹纹,在递归归标记对象象时会用到到,ctxx-immmuneeLimiit用来限限定堆的标标记范围。 函函数dvmmHeappBegiinMarrkSteep调用另另外一个函函数creeateMMarkSStackk来初始化化Markk Staack,它它的实现如如下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片statiic boool ccreatteMarrkStaack(GGcMarrkStaack *stacck) aasserrt(sttack != NNULL); ssize_t

51、 leengthh = ddvmHeeapSoourceeGetIIdeallFoottprinnt() * siizeoff(Objject*) / (sizeeof(OObjecct) + HEAAP_SOOURCEE_CHUUNK_OOVERHHEAD); mmadviise(sstackk-baase, lenggth, MADVV_NORRMAL); sstackk-toop = stacck-bbase; rreturrn trrue; 这这个函数定定义在文件件dalvvik/vvm/allloc/MarkkSweeep.cppp中。 函函数creeateMMarkSStackk根

52、据最坏坏情况来设设置Marrk Sttack的的长度,也也就是用当当前堆的大大小除以对对象占用的的最小内存存得到的结结果。当前前堆的大小小可以通过过函数dvvmHeaapSouurceGGetIddealFFootpprintt来获得。在堆上分分配的对象象,都是从从Objeect类继继承下来的的,因此,每每一个对象象占用的最最小内存是是sizeeof(OObjecct)。由由于在为对对象分配内内存时,还还需要额外外的内存来来保存管理理信息,例例如实际分分配给对象象的内存字字节数。这这些额外的的管理信息息占用的内内存字节数数通过宏HHEAP_SOURRCE_CCHUNKK_OVEERHEAAD来

53、描述述。 由由于Marrk Sttack实实际上是一一个Objject指指针数组,因因此有了上上面的信息息之后,我我们就可以以计算出MMark Stacck的长度度lenggth。MMark Stacck使用的的内存块在在Dalvvik虚拟拟机启动的的时候就创创建好的,具具体参考前前面一文,起起始地址位位于staack-basee中。由于于这块内存存开始的时时候被函数数madvvice设设置为MAADV_DDONTNNEED,因因此这里要要将它重新新设置为MMADV_NORMMAL,以以便可以通通知内核,这这块内存要要开始使用用了。 MMark Stacck的栈顶顶stacck-ttop指向向

54、的是Maark SStackk内存块的的起始位置置,以后就就会从这个个位置开始始由小到大大增长。 回回到函数ddvmHeeapBeeginMMarkSStep中中,ctxx-immmuneeLimiit记录的的实际上是是堆的起始始标记位置置。在此位位置之前的的对象,都都不会被GGC。这个个位置是通通过函数ddvmHeeapSoourceeGetIImmunneLimmit来确确定的,它它的实现如如下所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片void *dvmmHeappSourrceGeetImmmuneLLimitt(boool is

55、sParttial) iif (iisParrtiall) rreturrn hss2heaap(gHHs)-basee; elsse rreturrn NUULL; 这这个函数定定义在文件件dalvvik/vvm/allloc/HeappSourrce.ccpp中。 当当参数issParttial等等于truue时,函函数dvmmHeappSourrceGeetImmmuneLLimitt返回的是是Actiive堆的的起始位置置,否则的的话就返回回NULLL值。也就就是说,如如果当前执执行的GCC只要求回回收部分垃垃圾,那么么就只回收收Actiive堆的的垃圾,否否则的话,就就同时回收收Ac

56、tiive堆和和Zygoote堆的的垃圾。 33. dvvmHeaapMarrkRoootSett 函函数dvmmHeappMarkkRoottSet用用来的标记记根集对象象,它的实实现如下所所示:cpp vieew pllain copyy 在COODE上查查看代码片片派生到我我的代码片片/* Maark tthe sset oof rooot oobjeccts. * * Thhingss we needd to scann: * - Systtem cclassses ddefinned bby rooot cclasssloadder * - For eachh thrread: *

57、- Innterppreteed sttack, froom toop too cuurFraame * - Dalvvik rregissterss (arrgs + loccal vvars) * - JNNI loocal refeerencces * - Auutomaatic VM llocall refferennces (TraackeddAllooc) * - Asssociiatedd Thrread/VMThhreadd objject * - ThhreaddGrouups (coulld trrack & sttart withh theese iinsteead oo

58、f woorkinng * uppwardd froom Thhreadds) * - Exxcepttion currrentlly beeing throown, if ppreseent * - JNI globbal rreferrencees * - Inteernedd strring tablle * - Primmitivve cllassees * - Speccial objeects * - gDDvm.ooutOffMemooryObbj * - Objeects in ddebuggger objeect rregisstry * * Doont needd: * -

59、 Natiive sstackk (foor inn-proogresss sttuff in tthe VVM) * - Thhe TrrackeedAllloc sstufff wattchess alll nattive VM rreferrencees. */ void dvmHHeapMMarkRRootSSet() GGcHeaap *ggcHeaap = gDvmm.gcHHeap; ddvmMaarkImmmuneeObjeects(gcHeeap-markkConttext.immuuneLiimit); ddvmViisitRRootss(roootMarrkObjject

60、VVisittor, &gcHHeap-marrkConntextt); 这这个函数定定义在文件件dalvvik/vvm/allloc/MarkkSweeep.cppp中。 通通过注释我我们可以看看到根集对对象都包含含了哪些对对象。总的的来说,就就是包含两两大类对象象。一类是是Dalvvik虚拟拟机内部使使用的全局局对象,另另一类是应应用程序正正在使用的的对象。前前者会维护护在内部的的一些数据据结构中,例例如Hassh表,后后者维护在在调用栈中中。对这些些根集对象象进行标记记都是通过过函数dvvmVissitRooots和和回调函数数roottMarkkObjeectViisitoor进行的的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论