ART Heap学习笔记
boot.art@classes.dex和boot.art@classes.oat在系统第一次启动时由系统类生成。
boot.art@classes.dex是需要预加载的类对象。启动后直接映射到内存中,省去每次启动时创建预加载的类对象
boot.art@classes.oat是预加载类的oat文件。
Space
Paste_Image.pngImageSpace描述的是Image Space(连续空间),DlMallocSpace描述的是Zygote Space和Allocation Space(连续空间,可分配,匿名共享内存块),LargeObjectMapSpace描述的是Large Object Space(非连续空间,可分配)。
GC
6种垃圾收集器
串行和并行
FullMarkSweep(application and Zygote heap)、PartialMarkSweep(application heap but not the Zygote)和StickyMarkSweep(only free objects allocated since the last GC)
非并行GC
-
调用子类实现的成员函数InitializePhase执行GC初始化阶段。
-
挂起所有的ART运行时线程。
-
调用子类实现的成员函数MarkingPhase执行GC标记阶段。
-
调用子类实现的成员函数ReclaimPhase执行GC回收阶段。
-
恢复第2步挂起的ART运行时线程。
-
调用子类实现的成员函数FinishPhase执行GC结束阶段。
并行GC:
-
调用子类实现的成员函数InitializePhase执行GC初始化阶段。
-
获取用于访问Java堆的锁。
-
调用子类实现的成员函数MarkingPhase执行GC并行标记阶段。
-
释放用于访问Java堆的锁。
-
挂起所有的ART运行时线程。
-
调用子类实现的成员函数HandleDirtyObjectsPhase处理在GC并行标记阶段被修改的对象。。
-
恢复第4步挂起的ART运行时线程。
-
重复第5到第7步,直到所有在GC并行阶段被修改的对象都处理完成。
-
获取用于访问Java堆的锁。
-
调用子类实现的成员函数ReclaimPhase执行GC回收阶段。
-
释放用于访问Java堆的锁。
-
调用子类实现的成员函数FinishPhase执行GC结束阶段。
live bitmap为上次gc后存活的对象,mark bitmap为当前gc时存活的对象。
回收的对象为livebitmap为1,但是mark bitmap为0的对象
分配的对象对齐到8,分配的对象的地址的最低三位总是0
bitmap(int数组)的大小为(heap size)/8/32*4
Mod Union Table
记录不会被回收的Space的对象对会被回收的Space的引用
分配对象
Paste_Image.png当满足以下三个条件时,在large object heap上分配,否则在zygote或者allocation space上分配:
-
请求分配的内存大于等于Heap类的成员变量large_object_threshold_指定的值。这个值等于3 * kPageSize,即3个页面的大小。
-
已经从Zygote Space划分出Allocation Space,即Heap类的成员变量have_zygote_space_的值等于true。
-
被分配的对象是一个原子类型数组,即byte数组、int数组和boolean数组等。
分配完后,如果已分配空间大小大于concurrent_start_bytes_,则执行一次并行GC。如果分配失败,抛出OOM
LargeObjectMapSpace的分配是通过mmap创建一个匿名共享内存,zygote space和allocation space则是通过mspace分配内存。
当第一次尝试分配内存失败后,会尝试进行sticky,partial,full gc(回收力度依次加大,不进行软引用的回收),每次gc后都会尝试分配内存,如果成功就停止。
kGcTypeSticky只回收上次GC后在Allocation Space中新分配的垃圾对象;kGcTypePartial只回收Allocation Space的垃圾对象;kGcTypeFull同时回收Zygote Space和Allocation Space的垃圾对象
经过前面三种类型的GC后还是不能成功分配到内存,那就说明能够回收的内存还是太小了,因此,这时候只能通过在允许范围内增长堆的大小来满足内存分配请求了。如果在允许范围内增长了堆的大小还是不能成功分配到请求的内存,那就只能出最后的一个大招了。
最后的大招是首先执行一个类型为kGcTypeFull的、要求回收那些只被软引用对象引用的对象的GC,接着再在允许范围内增长堆大小的前提下尝试分配内存。这一次如果还是失败,那就真的是内存不足了。