Android 内存回收机制

Android虚拟机(art或者Dalvik)也是jvm的一种,它们的内存回收机制基本一致。它们使用的都是分代垃圾回收器,就是把整个堆内存区域分成“新生代(Young Generation)”、“老年代(Old Generation)”、“永久代(PermanentGeneration)”,如下图所示:
image.png
1、Young Generation

新生代的内存区域又被分成三部分,分别是Eden、s0、s1,在hotspot中它们的默认是比例是8:1:1,为什么是这个比例下面会解释。每次分配新对象都是从Eden中分配,新生代的gc过程是,通过gc root对象(gc root对象包括:在栈帧中的对象、native栈中的对象、静态对象)标记存活的对象,并且把存活的对象拷贝到s0中然后清空Eden,接下来的gc又会把Eden和s0存活的对象拷贝到s1中,s0和是s1总有一个是空闲的,gc过程就是把Eden和其中一个s的存活对象拷贝到另一个s中,然后清空s和Eden。为什么Eden:s0:s1是8:1:1呢?那是因为新生代对象经过一次gc后存活的概率只有5%左右,之前IBM统计过,正是因为新生代经过gc后存活的对象很少,才会使用拷贝擦除这种方法。gc最快的方法就是把没有被gc root对象直接引用或者间接引用的对象标记为无效,但是这样势必会造成大量的内存碎片,所以综合考虑最终在新生代使用拷贝擦除这种算法

2、Old Generation

在新生代中经过多次gc后仍然存活的对象则会晋升为老年代对象。老年代对象的gc比新生代更耗时。
老年代的gc过程是:

  1. 先从gc root对象出发,标记能被gc root对象直接引用或者间接引用的对象为存活的

  2. 把存活的对象移到内存区域的一端并对齐,然后清空未标记为存活的对象。在老年代区域中,gc后对象的存活的几率会比较大,所以一般不用拷贝擦除的方法来回收对象,如果使用拷贝擦除的方法的话需要进行大量的拷贝工作效率肯定不高,而且还必须要有一块空闲的内存用来存放存活的对象,这样势必也会造成内存的利用率不高

3、Android内存回收的特点

由于Android作为一个终端,需要快速的响应用户的操作,而gc过程又要暂停所有的线程,所以必须要保证的gc的时间不会太长。在Android中应用启动的时候一般会分配一段内存作为初始内存,在应用的运行过程需要创建一个新对象,而初始分配的内存空间已经无法提供足够的内存,此时就会触发gc,如果gc过后还是没有足够内存则会对堆内存进行扩容,扩容到最大值后还是没有提供足够的内存则会再进行一次gc,这次gc会把软引用也清空,如果仍然没有足够的内存就抛出oom。

总结起来Android系统不会一次性就把堆内存分配给应用进程,这样会导致gc的时间很长,用户的操作长时间得不到响应,而是分步给应用进程的堆内存进行扩容直到最大限制值

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容