![Dalvik虚拟机为新创建对象分配内存的过程分析_第1页](http://file4.renrendoc.com/view/17ea80030193b6c3a1558f26b7a6b0c7/17ea80030193b6c3a1558f26b7a6b0c71.gif)
![Dalvik虚拟机为新创建对象分配内存的过程分析_第2页](http://file4.renrendoc.com/view/17ea80030193b6c3a1558f26b7a6b0c7/17ea80030193b6c3a1558f26b7a6b0c72.gif)
![Dalvik虚拟机为新创建对象分配内存的过程分析_第3页](http://file4.renrendoc.com/view/17ea80030193b6c3a1558f26b7a6b0c7/17ea80030193b6c3a1558f26b7a6b0c73.gif)
![Dalvik虚拟机为新创建对象分配内存的过程分析_第4页](http://file4.renrendoc.com/view/17ea80030193b6c3a1558f26b7a6b0c7/17ea80030193b6c3a1558f26b7a6b0c74.gif)
![Dalvik虚拟机为新创建对象分配内存的过程分析_第5页](http://file4.renrendoc.com/view/17ea80030193b6c3a1558f26b7a6b0c7/17ea80030193b6c3a1558f26b7a6b0c75.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Dalvik虚拟机为新创建对象分配内存的过程分析在前面一文中,我们分析了Dalvik虚拟机创建Java堆的过程。有了Java堆之后,Dalvik虚拟机就可以在上面为对象分配内存了。在Java堆为对象分配内存需要解决内存碎片和内存不足两个问题。要解决内存碎片问题,就要找到一块大小最合适的空闲内存分配给对象使用。而内存不足有可能是内存配额用完引起的,也有可能是垃圾没有及时回收引起的,要区别对待。本文就详细分析Dalvik虚拟机是如何解决这些问题的。内存碎片问题其实是一个通用的问题,不单止Dalvik虚拟机在Java堆为对象分配内存时会遇到,C库的malloc函数在分配内存时也会遇到。Android系统使用的C库bionic使用了写的dlmalloc内存分配器。也就是说,我们调用函数malloc的时候,使用的是dlmalloc内存分配器来分配内存。这是一个成熟的内存分配器,可以很好地解决内存碎片问题。关于dlmalloc内存分配器的设计,可以参考这篇文章:。前面一文提到,Dalvik虚拟机的Java堆的底层实现是一块匿名共享内存,并且将其抽象为C库的一个mspace,如图1所示:于是,Dalvik虚拟机就很机智地利用C库里面的dlmalloc内存分配器来解决内存碎片问题!为了应对可能面临的内存不足问题,Dalvik虚拟机采用一种渐进的方法来为对象分配内存,直到尽了最大努力,如图2所示:接下来,我们就详细分析这个过程,以便可以了解Dalvik虚拟机是如何解决内存不足问题的,以及分配出来的内存是如何管理的。Dalvik虚拟机实现了一个dvmAllocObject函数。每当Dalvik虚拟机需要为对象分配内存时,就会调用函数dvmAllocObject。例如,当Dalvik虚拟机的解释器遇到一个new指令时,它就会调用函数dvmAllocObject,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片HANDLE_OPCODE(OP_NEW_INSTANCE/*vAA,class@BBBB*/){ClassObject*clazz;Object*newObj;EXPORT_PC();vdst=INST_AA(inst);ref=FETCH(1);clazz=dvmDexGetResolvedClass(methodClassDex,ref);if(clazz==NULL){clazz=dvmResolveClass(curMethod->clazz,ref,false);}newObj=dvmAllocObject(clazz,ALLOC_DONT_TRACK);SET_REGISTER(vdst,(u4)newObj);}FINISH(2);OP_END这个代码段定义在文件dalvik/vm/mterp/out/InterpC-portable.cpp中。关于Dalvik虚拟机的解释器的实现,可以参考一文,上面这段代码首先是找到要创建的对象的类型clazz,接着以其作为参数调用函数dvmAllocObject为要创建的对象分配内存。另外一个参数ALLOC_DONT_TRACK是告诉Dalvik虚拟机的堆管理器,要分配的对象是一个根集对象,不需要对它进行跟踪。因为根集对象在GC时是会自动被追踪处理的。函数dvmAllocObject的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片Object*dvmAllocObject(ClassObject*clazz,intflags){Object*newObj;assert(clazz!=NULL);assert(dvmIsClassInitialized(clazz)||dvmIsClassInitializing(clazz));/*allocateonGCheap;memoryiszeroedout*/newObj=(Object*)dvmMalloc(clazz->objectSize,flags);if(newObj!=NULL){DVM_OBJECT_INIT(newObj,clazz);dvmTrackAllocation(clazz,clazz->objectSize);/*notifyDDMS*/}returnnewObj;}这个函数定义在文件dalvik/vm/alloc/Alloc.cpp中。函数dvmAllocObject调用函数dvmMalloc从Java堆中分配一块指定大小的内存给新创建的对象使用。如果分配成功,那么接下来就先使用宏DVM_OBJECT_INIT来初始化新创建对对象的成员变量clazz,使得新创建的对象可以与某个特定的类关联起来,接着再调用函数dvmTrackAllocation记录当前的内存分配信息,以便通知DDMS。函数dvmMalloc返回的只是一块内存地址,这是没有类型的。但是由于每一个Java对象都是从Object类继承下来的,因此,函数dvmAllocObject可以将获得的没有类型的内存块强制转换为一个Object对象。Object类的定义如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片structObject{/*ptrtoclassobject*/ClassObject*clazz;/**Awordcontainingeithera"thin"lockora"fat"monitor.See*thecommentsinSync.cforadescriptionofitslayout.*/u4lock;};这个类定义在文件dalvik/vm/oo/Object.h中。Object类有两个成员变量:clazz和lock。其中,成员变量clazz的类型为ClassObject,它对应于Java层的java.lang.Class类,用来描述对象所属的类。成员变量lock是一个锁,正是因为有了这个成员变量,在Java层中,每一个对象都可以当锁使用。理解了Object类的定义之后,我们继续分析函数dvmMalloc的实现,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片void*dvmMalloc(size_tsize,intflags){void*ptr;dvmLockHeap();/*Tryashardaspossibletoallocatesomememory.*/ptr=tryMalloc(size);if(ptr!=NULL){/*We'vegotthememory.*/if(gDvm.allocProf.enabled){Thread*self=dvmThreadSelf();gDvm.allocProf.allocCount++;gDvm.allocProf.allocSize+=size;if(self!=NULL){self->allocProf.allocCount++;self->allocProf.allocSize+=size;}}}else{/*Theallocationfailed.*/if(gDvm.allocProf.enabled){Thread*self=dvmThreadSelf();gDvm.allocProf.failedAllocCount++;gDvm.allocProf.failedAllocSize+=size;if(self!=NULL){self->allocProf.failedAllocCount++;self->allocProf.failedAllocSize+=size;}}}dvmUnlockHeap();if(ptr!=NULL){/**Ifcallerhasn'taskedusnottotrackit,addittothe*internaltrackinglist.*/if((flags&ALLOC_DONT_TRACK)==0){dvmAddTrackedAlloc((Object*)ptr,NULL);}}else{/**Theallocationfailed;throwanOutOfMemoryError.*/throwOOME();}returnptr;}这个函数定义在文件dalvik/vm/alloc/Heap.cpp中。在Java堆分配内存前后,要对Java堆进行加锁和解锁,避免多个线程同时对Java堆进行操作。这分别是通过函数dvmLockHeap和dvmunlockHeap来实现的。真正执行内存分配的操作是通过调用另外一个函数tryMalloc来完成的。如果分配成功,则记录当前线程成功分配的内存字节数和对象数等信息。否则的话,就记录当前线程失败分配的内存字节数和对象等信息。有了这些信息之后,我们就可以通过DDMS等工具来对应用程序的内存使用信息进行统计了。最后,如果分配内存成功,并且参数flags的ALLOC_DONT_TRACK位设置为0,那么需要将新创建的对象增加到Dalvik虚拟机内部的一个引用表去。保存在这个内部引用表的对象在执行GC时,会添加到根集去,以便可以正确地判断对象的存活。另一方面,如果分配内存失败,那么就是时候调用函数throwOOME抛出一个OOM异常了。我们接下来继续分析函数tryMalloc的实现,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticvoid*tryMalloc(size_tsize){void*ptr;ptr=dvmHeapSourceAlloc(size);if(ptr!=NULL){returnptr;}if(gDvm.gcHeap->gcRunning){dvmWaitForConcurrentGcToComplete();}else{gcForMalloc(false);}ptr=dvmHeapSourceAlloc(size);if(ptr!=NULL){returnptr;}ptr=dvmHeapSourceAllocAndGrow(size);if(ptr!=NULL){returnptr;}gcForMalloc(true);ptr=dvmHeapSourceAllocAndGrow(size);if(ptr!=NULL){returnptr;}returnNULL;}这个函数定义在文件dalvik/vm/alloc/Heap.cpp中。函数tryMalloc的执行流程就如图2所示:1.调用函数dvmHeapSourceAlloc在Java堆上分配指定大小的内存。如果分配成功,那么就将分配得到的地址直接返回给调用者了。函数dvmHeapSourceAlloc在不改变Java堆当前大小的前提下进行内存分配,这是属于轻量级的内存分配动作。2.如果上一步内存分配失败,这时候就需要执行一次GC了。不过如果GC线程已经在运行中,即gDvm.gcHeap->gcRunning的值等于true,那么就直接调用函数dvmWaitForConcurrentGcToComplete等到GC执行完成就是了。否则的话,就需要调用函数gcForMalloc来执行一次GC了,参数false表示不要回收软引用对象引用的对象。3.GC执行完毕后,再次调用函数dvmHeapSourceAlloc尝试轻量级的内存分配操作。如果分配成功,那么就将分配得到的地址直接返回给调用者了。4.如果上一步内存分配失败,这时候就得考虑先将Java堆的当前大小设置为Dalvik虚拟机启动时指定的Java堆最大值,再进行内存分配了。这是通过调用函数dvmHeapSourceAllocAndGrow来实现的。5.如果调用函数dvmHeapSourceAllocAndGrow分配内存成功,则直接将分配得到的地址直接返回给调用者了。6.如果上一步内存分配还是失败,这时候就得出狠招了。再次调用函数gcForMalloc来执行GC。参数true表示要回收软引用对象引用的对象。7.GC执行完毕,再次调用函数dvmHeapSourceAllocAndGrow进行内存分配。这是最后一次努力了,成功与事都到此为止。这里涉及到的关键函数有三个,分别是dvmHeapSourceAlloc、dvmHeapSourceAllocAndGrow和gcForMalloc。后面一个我们在接下来一篇文章分析Dalvik虚拟机的垃圾收集过程时再分析。现在重点分析前面两个函数。函数dvmHeapSourceAlloc的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片void*dvmHeapSourceAlloc(size_tn){HS_BOILERPLATE();HeapSource*hs=gHs;Heap*heap=hs2heap(hs);if(heap->bytesAllocated+n>hs->softLimit){returnNULL;}void*ptr;if(gDvm.lowMemoryMode){ptr=mspace_malloc(heap->msp,n);if(ptr==NULL){returnNULL;}uintptr_tzero_begin=(uintptr_t)ptr;uintptr_tzero_end=(uintptr_t)ptr+n;uintptr_tbegin=ALIGN_UP_TO_PAGE_SIZE(zero_begin);uintptr_tend=zero_end&~(uintptr_t)(SYSTEM_PAGE_SIZE-1);if(begin<end){madvise((void*)begin,end-begin,MADV_DONTNEED);memset((void*)end,0,zero_end-end);zero_end=begin;}memset((void*)zero_begin,0,zero_end-zero_begin);}else{ptr=mspace_calloc(heap->msp,1,n);if(ptr==NULL){returnNULL;}}countAllocation(heap,ptr);if(gDvm.gcHeap->gcRunning||!hs->hasGcThread){returnptr;}if(heap->bytesAllocated>heap->concurrentStartBytes){dvmSignalCond(&gHs->gcThreadCond);}returnptr;}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。从前面一文可知,gHs是一个全局变量,它指向一个HeapSource结构。在这个HeapSource结构中,有一个heaps数组,其中第一个元素描述的是Active堆,第二个元素描述的是Zygote堆。通过宏hs2heap可以获得HeapSource结构中的Active堆,保存在本地变量heap中。宏hs2heap的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片#definehs2heap(hs_)(&((hs_)->heaps[0]))这个宏定义在文件dalvik/vm/alloc/HeapSource.cpp中。在前面一文中,我们解释了Java堆有起始大小、最大值、增长上限值、最小空闲值、最大空闲值和目标利用率等参数。在Dalvik虚拟机内部,还有一个称为软限制(SoftLimit)的参数。堆软限制是一个与堆目标利率相关的参数。Java堆的SoftLimit开始的时候设置为最大允许的整数值。但是每一次GC之后,Dalvik虚拟机会根据Active堆已经分配的内存字节数、设定的堆目标利用率和Zygote堆的大小,重新计算SoftLimit,以及别外一个称为理想大小(IdealSize)的值。如果此时只有一个堆,即只有Active堆没有Zygote堆,那么SoftLimit就等于IdealSize。如果此时有两个堆,那么IdealSize就等于Zygote堆的大小再加上SoftLimit值,其中SoftLimit值就是此时Active堆的大小,它是根据Active堆已经分配的内存字节数和设定的堆目标利用率计算得到的。这个SoftLimit值到底有什么用呢?它主要是用来限制Active堆无节制地增长到最大值的,而是要根据预先设定的堆目标利用率来控制Active有节奏地增长到最大值。这样可以更有效地使用堆内存。想象一下,如果我们一开始Active堆的大小设置为最大值,那么就很有可能造成已分配的内存分布在一个很大的范围。这样随着Dalvik虚拟机不断地运行,Active堆的内存碎片就会越来越来重。相反,如果我们施加一个SoftLimit,那可以尽量地控制已分配的内存都位于较紧凑的范围内。这样就可以有效地减少碎片。回到函数dvmHeapSourceAlloc中,参数n描述的是要分配的内存大小,而heap->bytesAllocated描述的是Active堆已经的内存大小。由于函数dvmHeapSourceAlloc是不允许增长Active堆的大小的,因此当(heap->bytesAllocated+n)的值大于Active堆的SoftLimit时,就直接返回一个NULL值表示分配内存失败。如果要分配的内存不会超过Active堆的SoftLimit,那么就要考虑Dalivk虚拟机在启动时是否指定了低内存模式。我们可以通过-XX:LowMemoryMode选项来让Dalvik虚拟机运行低内存模式下。在低内存模式和非低内存模块中,对象内存的分配方式有所不同。在低内存模式中,Dalvik虚拟机假设对象不会马上就使用分配到的内存,因此,它就通过系统接口madvice和MADV_DONTNEED标志告诉内核,刚刚分配出去的内存在近期内不会使用,内核可以该内存对应的物理页回收。当分配出去的内存被使用时,内核就会重新给它映射物理页,这样就可以做按需分配物理内存,适合在内存小的设备上运行。这里有三点需要注意。第一点是Dalvik虚拟机要求分配给对象的内存初始化为0,但是在低内存模式中,是使用函数mspace_malloc来分配内存,该函数不会将分配的内存初始化为0,因此我们需要自己去初始化这块内存。第二点是对于被系统接口madvice标记为MADV_DONTNEED的内存,是不需要我们将它初始化为0的,一来是因为这是无用功(对应的物理而可能会被内核回收),二来是因为当这些内存在真正使用时,内核在为它们映射物理页的同时,也会同时映射的物理页初始为0。第三点是在调用系统接口madvice时,指定的内存地址以及内存大小都必须以页大小为边界的,但是函数mspace_malloc分配出来的内存的地址只能保证对齐到8个字节,因此,我们是有可能不能将所有分配出来的内存都通过系统接口madvice标记为MADV_DONTNEED的。这时候对于不能标记为MADV_DONTNEED的内存,就需要调用memset来将它们初始化为0。在非低内存模式中,处理的逻辑就简单很多了,直接使用函数mspace_calloc在Active堆上分配指定的内存大小即可,同时该函数还会将分配的内存初始化为0,正好是可以满足Dalvik虚拟机的要求。注意,由于内存碎片的存在,即使是要分配的内存没有超出Active堆的SoftLimit,在调用函数mspace_malloc和函数mspace_calloc的时候,仍然有可能出现无法成功分配内存的情况。在这种情况下,都直接返回一个NULL值给调用者。在分配成功的情况下,函数dvmHeapSourceAlloc还需要做两件事情。第一件事情是调用函数countAllocation来计账,它的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticvoidcountAllocation(Heap*heap,constvoid*ptr){assert(heap->bytesAllocated<mspace_footprint(heap->msp));heap->bytesAllocated+=mspace_usable_size(ptr)+HEAP_SOURCE_CHUNK_OVERHEAD;heap->objectsAated++;HeapSource*hs=gDvm.gcHeap->heapSource;dvmHeapBitmapSetObjectBit(&hs->liveBits,ptr);assert(heap->bytesAllocated<mspace_footprint(heap->msp));}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。函数countAllocation要计的账有三个:1.记录Active堆当前已经分配的字节数。2.记录Active堆当前已经分配的对象数。3.调用函数dvmHeapBitmapSetObjectBit将新分配的对象在LiveHeapBitmap上对应的位设置为1,也就是说将新创建的对象标记为是存活的。关于LiveHeapBitmap,可以参考前面一文。回到函数dvmHeapSourceAlloc中,它需要做的第二件事情是检查当前Active堆已经分配的字节数是否已经大于预先设定的ConcurrentGC阀值heap->concurrentStartBytes。如果大于的话,那么就需要通知GC线程执行一次ConcurrentGC。当然,如果当前GC线程已经在进行垃圾回收,那么就不用通知了。当gDvm.gcHeap->gcRunning的值等于true时,就表示GC线程正在进行垃圾回收。这样,函数dvmHeapSourceAlloc的实现就分析完成了,接下来我们继续分析另外一个函数dvmHeapSourceAllocAndGrow的实现,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片void*dvmHeapSourceAllocAndGrow(size_tn){HeapSource*hs=gHs;Heap*heap=hs2heap(hs);void*ptr=dvmHeapSourceAlloc(n);if(ptr!=NULL){returnptr;}size_toldIdealSize=hs->idealSize;if(isSoftLimited(hs)){hs->softLimit=SIZE_MAX;ptr=dvmHeapSourceAlloc(n);if(ptr!=NULL){snapIdealFootprint();returnptr;}}ptr=heapAllocAndGrow(hs,heap,n);if(ptr!=NULL){snapIdealFootprint();}else{setIdealFootprint(oldIdealSize);}returnptr;}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。函数dvmHeapSourceAllocAndGrow首先是在不增加Active堆的前提下,调用我们前面分析的函数dvmHeapSourceAlloc来分配大小为n的内存。如果分配成功,那么就可以直接返回了。否则的话,继续往前处理。在继续往前处理之前,先记录一下当前Zygote堆和Active堆的大小之和oldIdealSize。这是因为后面我们可能会修改Active堆的大小。当修改了Active堆的大小,但是仍然不能成功分配大小为n的内存,那么就需要恢复之前Zygote堆和Active堆的大小。如果Active堆设置有SoftLimit,那么函数isSoftLimited的返回值等于true。在这种情况下,先将SoftLimit去掉,再调用函数dvmHeapSourceAlloc来分配大小为n的内存。如果分配成功,那么在将分配得到的地址返回给调用者之前,需要调用函数snapIdealFootprint来修改Active堆的大小。也就是说,在去掉Active堆的SoftLimit之后,可以成功地分配到大小为n的内存,这时候就需要相应的增加SoftLimit的大小。如果Active堆没有设置SoftLimit,或者去掉SoftLimit之后,仍然不能成功地在Active堆上分配在大小为n的内存,那么这时候就得出大招了,它会调用函数heapAllocAndGrow将Java堆的大小设置为允许的最大值,然后再在Active堆上分配大小为n的内存。最后,如果能成功分配到大小为n的内存,那么就调用函数snapIdealFootprint来重新设置Active堆的当前大小。否则的话,就调用函数setIdealFootprint来恢复之前Active堆的大小。这是因为虽然分配失败,但是前面仍然做了修改Active堆大小的操作。为了更好地理解函数dvmHeapSourceAllocAndGrow的实现,我们继续分析一下涉及到的函数isSoftLimited、setIdealFootprint、snapIdealFootprint和heapAllocAndGrow的实现。函数isSoftLimited的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticboolisSoftLimited(constHeapSource*hs){/*softLimitwillbeeitherSIZE_MAXorthelimitforthe*activemspace.idealSizecanbegreaterthansoftLimit*ifthereismorethanoneheap.Ifthereisonlyone*heap,anon-SIZE_MAXsoftLimitshouldalwaysbethesame*asidealSize.*/returnhs->softLimit<=hs->idealSize;}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。根据我们前面的分析,hs->softLimit描述的是Active堆的大小,而hs->idealSize描述的是Zygote堆和Active堆的大小之和。当只有一个堆时,即只有Active堆时,如果设置了SoftLimit,那么它的大小总是等于Active堆的大小,即这时候hs->softLimit总是等于hs->idealSize。如果没有设置SoftLimit,那么它的值会被设置为SIZE_MAX值,这会就会保证hs->softLimit大于hs->idealSize。也就是说,当只有一个堆时,函数isSoftLimited能正确的反映Active堆是否设置有SoftLimit。当有两个堆时,即Zygote堆和Active堆同时存在,那么如果设置有SoftLimit,那么它的值就总是等于Active堆的大小。由于hs->idealSize描述的是Zygote堆和Active堆的大小之和,因此就一定可以保证hs->softLimit小于等于hs->idealSize。如果没有设置SoftLimit,即hs->softLimit的值等于SIZE_MAX,那么就一定可以保证hs->softLimit的值大于hs->idealSize的值。也就是说,当有两个堆时,函数isSoftLimited也能正确的反映Active堆是否设置有SoftLimit。函数setIdealFootprint的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticvoidsetIdealFootprint(size_tmax){HS_BOILERPLATE();HeapSource*hs=gHs;size_tmaximumSize=getMaximumSize(hs);if(max>maximumSize){LOGI_HEAP("ClamptargetGCheapfrom%zd.%03zdMBto%u.%03uMB",FRACTIONAL_MB(max),FRACTIONAL_MB(maximumSize));max=maximumSize;}/*Convertmaxintoasizethatappliestotheactiveheap.*Oldheapswillcountagainsttheidealsize.*/size_toverhead=getSoftFootprint(false);size_tactiveMax;if(overhead<max){activeMax=max-overhead;}else{activeMax=0;}setSoftLimit(hs,activeMax);hs->idealSize=max;}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。函数setIdealFootprint的作用是要将Zygote堆和Active堆的大小之和设置为max。在设置之前,先检查max值是否大于Java堆允许的最大值maximum。如果大于的话,那么就属于将max的值修改为maximum。接下为是以参数false来调用函数getSoftFootprint来获得Zygote堆的大小overhead。如果max的值大于Zygote堆的大小overhead,那么从max中减去overhead,就可以得到Active堆的大小activeMax。如果max的值小于等于Zygote堆的大小overhead,那么就说明要将Active堆的大小activeMax设置为0。最后,函数setIdealFootprint调用函数setSoftLimit设置Active堆的当前大小,并且将Zygote堆和Active堆的大小之和记录在hs->idealSize中。这里又涉及到两个函数getSoftFootprint和setSoftLimit,我们同样对它们进行分析。函数getSoftFootprint的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticsize_tgetSoftFootprint(boolincludeActive){HS_BOILERPLATE();HeapSource*hs=gHs;size_tret=oldHeapOverhead(hs,false);if(includeActive){ret+=hs->heaps[0].bytesAllocated;}returnret;}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。函数getSoftFootprint首先调用函数oldHeapOverhead获得Zygote堆的大小ret。当参数includeActive等于true时,就表示要返回的是Zygote堆的大小再加上Active堆当前已经分配的内存字节数的值。而当参数includeActive等于false时,要返回的仅仅是Zygote堆的大小。函数oldHeapOverhead的实现如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticsize_toldHeapOverhead(constHeapSource*hs,boolincludeActive){size_tfootprint=0;size_ti;if(includeActive){i=0;}else{i=1;}for(/*i=i*/;i<hs->numHeaps;i++){//TODO:includesizeofbitmaps?Ifso,don'tusebitsLen,listento.maxfootprint+=mspace_footprint(hs->heaps[i].msp);}returnfootprint;}这个函数定义在文件dalvik/vm/alloc/HeapSource.cpp中。从这里就可以看出,当参数includeActive等于true时,函数oldHeapOverhead返回的是Zygote堆和Active堆的大小之和,而当参数includeActive等于false时,函数oldHeapOverhead仅仅返回Zygote堆的大小。注意,hs->heaps[0]指向的是Active堆,而hs->heaps[1]指向的是Zygote堆。这一点可以参考前面一文。回到函数setIdealFootprint中,我们继续分析函数setSoftLimit的实现,如下所示:[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片staticvoidsetSoftLimit(HeapSource*hs,size_tsoftLimit){mspacemsp=hs->heaps[0].msp;size_tcurrentHeapSize=mspace_footprint(msp);if(softLimit<currentHeapSize){
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 关于彩虹小知识
- 2016山西道法试卷+答案+解析
- 超声引导下坐骨神经阻滞联合股神经阻滞在糖尿病患者膝关节以下截肢手术中的应用效果分析
- 机械设备行业采购工作总结
- 《华润药业员工培训教程手册》100-医药保健
- 二零二五年度建筑材料销售返利执行细则7篇
- 2025版物流企业战略发展规划合同范本3篇
- 二零二五年船舶通风系统安装与维护服务合同3篇
- 植草沟种植施工方案
- 邢台阳台石栏杆施工方案
- 中国绿色食品市场调查与分析报告
- 九年级下册沪教版上海化学5.2酸和碱的性质研究 课件
- ISO17025经典培训教材
- 手卫生依从性调查表
- 湖北教育出版社四年级下册信息技术教案
- 背景调查报告
- 五年级语文下册全册教材分析
- 业主委员会成员推荐表
- 九年级下册-2023年中考历史总复习知识点速查速记(部编版)
- GB/T 18103-2022实木复合地板
- 《叶圣陶先生二三事》第1第2课时示范公开课教学PPT课件【统编人教版七年级语文下册】
评论
0/150
提交评论