ART的GC流程概述

1引入foreground gc和background gc是为了对mark-sweep gc和compacting gc算法的优缺点进行扬长避短

2foreground gc和background gc的切换时机,foreground gc和background gc的算法选择

3如何知道应用程序时在前台还是后台呢?ActivityManagerService知道应用程序的每一个组件的运行状态,也就是他们当前是前台运行还是后台运行,从而得出程序是前台运行还是后台运行的结论。

4这是由于Foreground GC和Background GC的底层堆空间结构是一样的,因此发生Foreground GC和Background GC切换时,需要将当前存活的对象从一个Space转移到另外一个 Space上去?

5六种内存分配器:

kAllocatorTypeBumpPointer:表示在bump pointer space中分配任务

kAllocatorTypeTLAB:表示要在bump pointer space提供的线程局部分配缓冲区中进行分配对象。

kAllocatorTypeRosAlloc:表示要在RosAllocSpace分配对象

kAllocatorTypeDImalloc:表示要在DI malloc space 分配对象

kAllocatorTypeNonMoving:表示要在Non Moving Space分配对象。

kAllocatorTypeLOS:表示要在Large Object Space分配对象。

 

Heap类的成员函数AllocObject和AllocNonMovableObject使用的分配器类型分别是由成员变量 current_allocator_和current_non_moving_allocator_决定的。前者的值与当前使用的GC类型有关。当GC 类型发生变化时,就会调用Heap类的成员函数ChangeCollector来修改当前使用的GC,同时也会调用另外一个成员函数 ChangeAllocator来修改Heap类的成员变量current_allocator_的值。由于ART运行时只有一个Non-Moving Space,因此后者的值就固定为kAllocatorTypeNonMoving。对于Compacting GC,它们使用的分配器类型只可能为kAllocatorTypeTLAB或者kAllocatorTypeBumpPointer

根据当前使用的GC不同,Heap类的成员变量gc_plan_会被设置为不同的值,用来表示在分配对象过程中遇到内存不足时,应该执行的GC粒度。对于 Compacting GC来说,只有一种GC粒度可执行,那就是kGcTypeFull,实际上就是说对Bump Pointer Space的所有不可达对象进行回收。对于Mark-Sweep GC来说,有三种GC粒度可执行,分别是kGcTypeSticky、kGcTypePartial和kGcTypeFull。

 

 

clipboard

 

 

 

当分配的原子类型数组大小大于等于3个内存页时,就在Large Object Space中进行分配。如果指定了要在当前ART运行时线程的TLAB中分配对象,并且这时候当前ART运行时线程的TLAB的剩余大小大于请求分配的对象大小,那么就直接在当 前线程的TLAB中分配。ART运行时线程的TLAB实际上是来自于Bump Pointer Space上的,后面我们就可以看到这一点。 如果上面的条件都不成立,接下来就调用Heap类的成员函数TryToAllocate来进行分配了。Heap类的成员函数TryToAllocate会根据参数allocator
当ART运行时当前使用的GC发生切换时,ART运行时当前使用的分配器类型也会随着变化allocator指定的分配器是否与art运行时allocation stack有关,如果有关就需要 将刚才成功分配到的对象压入allocation stack 中,以便以后可以执行sticky gc.

 

第一件事情:前面提到,ART运行时线程的TLAB是来自于Bump Pointer Space的,而Bump Pointer Space是与Compacting GC相关的,Allocation Stack是与Sticky GC相关的,这就意味着Compacting GC不会执行Sticky类型的GC。
第二件事情:看分配器是否与concurrent gc相关,并且当前使用的gc就是一个concurrent gc如果条件都成立的话,就调用heap类的成员函数checkconcurrent gc检查是否需要发起一个concurrent gc请求。

这就意味着目前提供的Compacting GC都是非Concurrent的。不过以后是会提供具有Concurrent功能的Compacting GC的,称为Concurrent Copying GC。
调用RosAllocSpace类的成员函数Alloc分配的内存具有非法内存访问检查功能

Bump Pointer Space支持按块和按对象分配内存的方式。其中,按块分配的内存主要就是用来作ART运行时线程的TLAB的。分配出来的内存块有一个额外的BlockHeader,它主要是用来记录块的大小。

 

 

 

clipboard[1]

 

 

 

这意味着同构空间压缩只针对Ros Alloc Space或者Dl Malloc Space Mark-Sweep GC的Non Moving Space具有独立的地址空间。
同构空间压缩本身就是一个Compacting GC,只不过它是要将Main Space作为From Space,而Backup Space作为To Space。当压缩操作完成之后,再将Main Space和Backup进行交换。通过这种方式,就可以解决由于Main Space的内存碎片太多而引起的内存分配失败问题。
指向的是两个不同的Space,那么就使用Semi-Space GC来执行同构空间压缩操作;否则的话,就使用Mark-Compact GC来执行同构空间压缩操作。这是由于Semi-Space GC需要有两个不同的Space,而Mark-Compact GC只需要一个Space即可。
禁用Compacting GC的过程也分析完成了,它主要的目的就是要将当前使用的GC切换为Mark-Sweep GC,以便可以获得一个Main Space,然后再进一步将该Main Space设置为Non Movable Space,这样就相当于是增加了Non Movable Space的大小,因此就可以满足更多的Non Movable对象分配请求。
android 4.4art 的mark0sweep gc 到android5.0art增加了对compacting gc的支持,包括semi-space.generational semi-space 和mark-compact三种。

compacting gc和mark-sweepgc各有优劣,所谓compacting gc,就是再进行gc的时候,同事对堆空间进行压缩,以消除碎片,因此它的堆空间利用率就更高,但是也正因为堆空间的压缩,导致compacting gc的gc效率不如mark-sweep gc,不过,只要我们使用得到恰到,是能够同时发挥mark-sweep gc的长处的,当Android应用程序被激活在前台运行时,就使用Mark-Sweep GC,而当Android应用程序回退到后台运行时,就使用Compacting GC

为了达到上述目的,ART运行时内部有Foreground和Background两种GC之分。在ART运行时启动的时候,可以通过-Xgc和 -XX:BackgroundGC来指定Foreground GC和Background GC的类型,即具体是哪一种Mark-Sweep GC或者Compacting GC。由于Mark-Sweep GC和Compacting GC所需要的堆空间结构是不一样的,因此,当发生Foreground GC和Background GC切换时,ART运行时需要提供支持,以维护堆空间的正确性。

除了适合后台运行时之外,Compacting GC还适合用在内存分配时。在以往的Mark-Sweep GC时,由于碎片而产生的内存不足问题,是解决不了的,只能让应用程序OOM。但是有了Compacting GC之后,就可以在应用程序OOM之前,再作一次努力,那就是对原来的堆空间进行压缩一下,再尝试进行分配,这样就可以提高成功分配内存的概率。Compacting GC的最大特点就是会对堆空间进行压缩。这意味着对象在堆空间的位置是会发生变化的。但是对应用程序来说,这种对象位置的变化是要透明的。因 此,Compacting GC的最核心挑战就是在保持应用程序逻辑不变和正确的前提下,在需要的时候对对象的位置进行移动。所以在这篇文章里面,我们第一个要介绍的技术就是对象移 动技术。

 

{参考:罗升阳博客}

posted on 2015-12-29 12:59  小帅叔叔  阅读(683)  评论(0编辑  收藏  举报

导航