Android性能测试之内存泄露以及GC机制浅析(三)

Android 内存泄露以及GC机制浅析

今天来说说android当中的GC机制(garbage collector)

参考网上大神的文章:

http://blog.csdn.net/luoshengyang/article/details/41822747

http://blog.csdn.net/suifeng3051/article/details/48292193

 

前言:

最近研究性能,其中最重要的一个性能指标就是内存泄露。身为一个良好的测试人员,除了能找到内存泄露的原因,反馈给开发,更重要的是理解内存泄露的原因以及内存相关的原理,作为一个测试人员技术的提高。(只讨论Dalvik虚拟机,JVM不算在内啦)

 

内存泄露的原因:

前一片文章已经说明了Android中开发过程中可能出现内存泄露的几个点,这里解释一下代码原因,一句话,就是在堆内存中的引用没有被释放掉,导致GC机制没有成功回收这部分new出来的对象,当重复操作某一个步骤的时候,对象就会不断被分配,导致的OOM,应用就拜拜了,避免内存泄露有机会再讨论了,今天学习以下GC的原理。

 

时机:

什么时候会触发GC呢?老罗的博客写了4个函数,给出了4个时机:

1.堆上分配对象时内存不足触发的GC

2.已分配内存达到一定数量触发GC

3.准备oom的时候系统最后挣扎

4.手动触发System.gc

说白了就是堆内存不够了,要发生oom了或者开发手动GC了,就会触发GC机制,这个容易理解。

 

怎么样GC

Dalvik虚拟机的回收方式是一个叫分代式的方式来回收的,GC根据代的不同执行不同的GC。为什么要引入这个呢?因为在执行清理的时候,系统要知道哪些对象是可以回收,就会从头遍历系统一遍,这样耗时耗力,严重影响性能,而内存中的部分堆对象是经常使用的,每次都全部寻找一遍未免会造成资源浪费,于是引入了分代式GC

 Android性能测试之内存泄露以及GC机制浅析(三)_第1张图片

(图片来自http://jefferent.iteye.com/blog/1123677)

 

如图,分代式分为三个空间,年轻代,老年代和持久代。其中,年轻代又分为

一个Eden空间和两个Survivor空间。平常我们程序运行使用的是Eden空间,当这个空间占满了,会触发一次新生代的GC(Scavenge GC),这个时候会采用Mark-Sweep算法去标记并清除无用的对象(算法后面会提),那么垃圾对象就会被清除,存活对象会移动到Survivor任意一个空间,Eden空间被清除;然后,这个Survivor空间也满了,触发MS算法,清除垃圾对象,存活对象又会被移动到另一个Survivor空间,另一个Survivor空间又满了,那么可以判断这个对象是经常使用的,就移动到老年区了,移动到老年区的对象不会被普通的GC清除,android里面经常触发的是新生代GC机制,还有一个是Full GC,代表全部区域都触发,比较耗时耗CPUFull GC一般是老年区或者持久区满了,那么就会触发了。Android通过这个方式,分代来进行GC,有效利用了系统资源进行分配,额,手动触发的GC都是Full GC了,所以不建议开发者一直手动触发这个方法,程序会卡的。

还有一个持久区,放的是一些静态变量,没啥可说的。

 

两个算法:

这里说两个算法,一个是年轻代的GC,还有一个是老年代的GC,分别是复制,标记-清除(Mark-Sweep)和标记-压缩(Mark-Compact)算法。

Coping

根集扫描出存活对象,然后移动到另一个新的内存中去,年轻代GC就是用这种算法的。

 Android性能测试之内存泄露以及GC机制浅析(三)_第2张图片

(图片来自

http://blog.csdn.net/suifeng3051/article/details/48292193)

Mark-Sweep:

从根集开始扫描(根集,从当前线程的函数的引用开始扫描,然后标记,然后继续从当前线程继续扩展扫描,直到完结),当对象有引用,那么mark一下,完了之后就清除垃圾对象。

Mark-Compact:

和上面一个类似,但是多了个压缩的过程,我们知道Mark-Sweep之后清除垃圾对象,那么内存当中存在内存碎片,这个算法就是把碎片填满,老年代的Full GC采用这个。

 

 

 

 

你可能感兴趣的:(Android性能测试之内存泄露以及GC机制浅析(三))