《Dalvik虚拟机垃圾收集(GC)过程分析.docx》由会员分享,可在线阅读,更多相关《Dalvik虚拟机垃圾收集(GC)过程分析.docx(45页珍藏版)》请在优知文库上搜索。
1、DaIVik虚拟机垃圾收集(GC)过程分析前面我们分析了Oa1.vik虚拟机堆的创立过程,以及Java对象在堆上的分配过程。这些知识都是理解Ita1.vik虔拟批垃圾收集过程的基础。垃圾收集是一个发杂的过程,它要将那些不再被引用的对象进行回收,一方面要求Da1.vik虚拟机能鲂标记出哪些对象是不再被引用的.另一方面要求DfnVik虚拟机尽快地回收内存.防止陶用程序长时间停顿.本文就将详细分析Da1.Yik虚拟机是如何裤决上述问磔完成垃圾收集过程的.Da1.vik虚拟机使用Vark-Sweep算法来进行垃圾收集,顾名思义,Mark-Sweep算法就是为Mark和Sweep两个阶段进行垃圾回收。其
2、中,Mark阶段从根集(ROO1.Sc1.开始,递归地标记出当前所有被引用的时象,而Swwp阶段负贲回收那些没有被引用的对望.在分析Da1.vik虚拟机使用的Mark-SVCeP算法之前,我们先来了解一下什么情况下会触发GC.Da1.vik虚拟机在三种情况下会触发四种类里的GC.母一种类型GC使用一个GCSPCC结构体来描述,它的定义如下所示:cppviewp1.aincopy在C(三)E上杳看代码片源生到我的代码片structGcSpec(Iftrue,on1.ytheapp1.ictionheapisthreatened.*/boo1.isPartia1.:Iftrue,thetracei
3、srunconcurrent1.ywiththemutator.*/boo1.iSConcurren1.;Togg1.esforthesoftreferencec1.earingpo1.icy.*/boo1.doPreserve:Ana三eforthisgarbageco1.1.ectionmode./constchar*rcason;);这个结构体定义在文件dfi1.ik11a1.1.ocHeap.h,GcSpec结构体的各个成仍变球的含义如下所示:isPartia1.:为true时.表示仅仅回收Active堆的垃圾:为fa1.se时,表示同时回收Active堆和Zygote堆的坨圾.iSC
4、oncurrent:为IrUI1时,表示执行并行GC:为fa1.se时,表示执行非并行GC-doPreserve:为true时,表示在执行GC的过程中,不回收软引用引用的对象:为fa1.se时,表示在执行GC的过程中,回收软引用引用的对敛,reason:一个描述性的字符即“DaVIik虚拟机定义了四种类的GC,如下所示:cppVieVp1.aincopy在CoDE上查看代码片派生到我的代码片*Notenoughspaceforanordinary.Objecttobea1.1.ocated.*/externconstGcSec*GC_FOR_MA1.1.OC;*AutonaticGCtrigg
5、eredbyexceedingaheapoccupancythresho1.d./externconstGcSpec*GC_C(WcHRRENI;*Exp1.icitGCviaRuntiae.gc(),YMRuntimp.gc(),orSIG1.SR1./externconstGcSpec*GCEXP1.ICIT;*Fina1.attempttorec1.aimmemorybeforethrowinganOOM.*/externconstGcSpec*GC_BEFORE_(X)Y;这四个全同变量:声明在文件da1.vik/vm/a1.1.oc/Heap.h中。它们的含义如卜所示IGcjorji
6、ai1.oc:表示是在堆上分足对象时内存法乏触发的gc.GC_CONCtRREYT:表示是在已分配内存到达一定所之后触发的GC.GC1.XP1.ICIT:役示是应用程序调用System,gc、YMRUntimc.gc接11或者收到SIG1.SR1信号时触发的GC.GCHEFORE00M:表示是在准符拊OOM异常之前进行的最后努力而触发的GC。实际上,(X:FoRWAU.0C、GJCONC1.RRENT和CUBEFORE(KW-:种类型的GC都是在分泡时象的过程触发的,在前面一文,我们提到.Da1.vik虚拟机在JaYa堆匕分配对象的时候,在碰到分配失败的情况,会尝试门用函数gcForMa1.I
7、。C进行垃圾I收.函数KcForMii1.1.oc的实现如卜所示:eppviewp1.aincopy在CODE上查看代码片派生到我的代码片staticvoidgcForMa1.Ioc(boo1.c1earSofIReferences)constGcSpec*spec=CIearSOf1.ReferenCeS?GC_BEI:ORE_OOM:GCFORHA1.1.OC:dvfCo11cctGarbaeIntcrna1(spec);)这个函数定义在文件da1.vikv三a1.1.oc/Heap.cpp.参数C1.earSoftRefereCeS表示是否要对软引用引用的对象诳行回收,如果要对软引用引用
8、的对象进行回收,那么就说明当前内存是作常紧张的了,因此,这时候执行的就是GCBEFoREOoM类型的GG否则的话,执行的就是Gej7ORMA1.1.OC类型的GC.它们都是通过调用函数dmCO1.1.eCtGarbi1.ge1.ntCrnaI来执行的.在前面一文,我们也提到,当Da1.Vik虚拟机成功地在堆上分配一个对象之后,会IftiS一下当前分配的内存是否超出一个网值,如卜所示:cppvie.p1.aincopy在CoDE上查看代码片派生到我的代码片void*dvm1.1.eapSourceA1.Ioc(size_tn)HeapSource*hs=g1.1.s;Heap*heap=hs2h
9、eap(hs);if(heap-bytesA1.1.ocated+nhs-soft1.i11it)(returnNU1.1.;void*ptr;if(gDvm.1.owMrryModc)ptr=mspace_ma1Ioc(heap-msp,n);e1.se(ptr三-mspace_ca1.1.ex:(heap-msp,1.n);count11ocation(heap,ptr);if(heap-bytesA1.1.ocatedheap-concurren1.Star1.By1.cs)(dvmSignaICond(g1.1.s-gcThreadCond);returnptr:)这个函数定义在文件d
10、a1.vik/vm/a1.1.ocHeRPSCUrCacpp中”/数(1VfnUeapSourcetfIHoc成功地在Active堆上分配到一个对象之后,就会检食ACEiYe堆当前已经分配的内存(hea-bytesA1.1.ocated)是否大于预设的阀值concurrontStariBytos)如果大于,那么就会通过条件变量g1.1.s-gcThreadCond唤醒GC线程进行垃圾网收预设的阀值(heapConcurrentStartBytes是一个比指定的堆最小空闲内存小128K的数tf1.也就是说,当堆的空闲内缺乏时,我会触发SCONCURRENT类型的GCGC线程是Da1.vik虚拟机
11、启动的过程中创立的.它的执行体函数足gcDaeaonThread,实现如下所示:cppviewp1.aincopy在CoDE上IS看代码片派生到我的代码片staticvoid*gcDaemonThreaMBA1T);dVm1.ockMutex(gHs-gcThreadMutex);whi1.e(1.s-gcT1.rcadShutdowr!=true)(boo1.trim三fa1.se:if(gHs-gcThreadTrimNeeded)(iniresu1.t=dvmReIatiVeCondWait(AgHs-gcThreadCori,Sg1.1.s-gcThreadMutex,HEAP_TRI
12、M_ID1.E_TIME_MS0):if(resu1.t=ETIMEDOUD(/TimedoutwaitingforaGCrequest,schedu1.eaheaptrim./trim=true:e1.sedvf1.)WaitCond(gHs-gcThreadCond,SHs-cThreadMutex):dvm1.ck1.1.eap():ifgcRunning)(dvmChaneStatus(NU1.1.,THREAD_RuNN1.NG);if(trim)(trim1.1.eapsO;gJis-gcThreadTrimNeeded=fa1.se:e1.sedvmCo1.IectGarbage
13、Interna1.(GC_CONCVRRENT);g!1.s-gcThreadTrimNeeded=true;dvmChaneStatus(NU1.1.,THREADJMWAIT);dvmUn1.ockHeap():dv11ChaneStatus(NIU,THREAD.RUNNING);returnNU1.1.;)这个函数定义在文件da1.vik/vm/a1.IocZHeapSource.cp中。GC战程平时没事的时候,就无条件变量HHS-RcThrcadCtm1.上进行等待HEAPjRIMID1.EJnMEYS电秒(5000意杪.如果在heaptrim_id1.e_timems汽秒内都没有得
14、到执行GC的通知,那么它就词用函数trimeaps对JaVa堆进行裁剪,以便可以将墙上的一些没存使用到的内存交还给内核.函数trim1.eaps的实现可以参考前面一文。否则的话,就会调用函数dmCoIIeCIGarbage1.nterna1.迸行类型为GC工ONcIiRRENT的GG注卷函数gcDae三onThread在调用函数dvmCo1.IectGarbageInterna1.进行类型为GJCONCURRENT的GC之前,会先圜用函数dvakockHeap来锁定堆的.等到GC执行完毕,再调用函数dv三(Jn1.OCkHCaP来解除对堆的倾定。这与函数gcrMa1.1.oc调用函数dvCo1
15、.IectGarbageInterna1.进行类型为GCFoRMA1.1.OC和GCeoNCURRENT的GC是一样的。只不过,对堆进行Wi定和解锁的操作是在调用堆校上的函数dv&a1.1.oc进行的,具体可以参考前面一文.当应用程序调用SyStem.gc、VMRuntiae.gc接口,或者接收到SIGUSR1信号时,址终会调用到函数dvmCo1.Icc1.GarbdKc,它的实现如卜所示:cppvie.p1.aincopy在CoDE上查看代码片派生到我的代码片voiddvBCo11ectGar1.ae()if(gDn.disbIeExpIicitGc)return;dYm1.ock1.IeapO;dvmIaitForConcurrentCcToCom1.eteO;dvCo1.IectGarbiixeIntcrna1.(GCEXP1.ICIT):dvmUn1.ock1