-
GC_FOR_MALLOC: 表示是在堆上分配对象时内存不足触发的GC。
-
GC_CONCURRENT: 当我们应用程序的堆内存达到一定量,或者可以理解为快要满的时候,系统会自动触发GC操作来释放内存。
-
GC_EXPLICIT: 表示是应用程序调用System.gc、VMRuntime.gc接口或者收到SIGUSR1信号时触发的GC。
-
GC_BEFORE_OOM: 表示是在准备抛OOM异常之前进行的最后努力而触发的GC。
实际上,GC_FOR_MALLOC、GC_CONCURRENT和GC_BEFORE_OOM三种类型的GC都是在分配对象的过程触发的。而并发和非并发GC的区别主要在于前者在GC过程中,有条件地挂起和唤醒非GC线程,而后者在执行GC的过程中,一直都是挂起非GC线程的。并行GC通过有条件地挂起和唤醒非GC线程,就可以使得应用程序获得更好的响应性。但是同时并行GC需要多执行一次标记根集对象以及递归标记那些在GC过程被访问了的对象的操作,所以也需要花费更多的CPU资源。后文在Art的并发和非并发GC中我们也会着重说明下这两者的区别。
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执行完毕,再次调用函数dvmHeapSo