Android应用的内存优化总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuanguofeng/article/details/78789795

一、Android内存管理机制

1、Java对象的生命周期

Java对象的生命周期经历7个阶段,分别是创建阶段、应用阶段、不可见阶段、不可达阶段、收集阶段、终结阶段、对象控件重新分配阶段。

2、内存回收机制

内存的三个区域

内存会有三个区域,Yong Generation(年轻代)、Old Generation(年老代)、permanent Generation(持久代)。
其中年轻代里面又分为三个区,eden、S0、S1。

内存的处理过程:

1.对象创建后在Eden区域,

2.执行GC时,如果对象仍然存货,则复制到S0区。

3.当S0区满时,改区域存活对象将复制到S1区,然后S0清空,接下来S0和S1角色互换。

4.当第三部达到一定次数后,存活对象将被复制到Old Generation。

5.当这个对象在Old Generation区域挺溜的时间达到一定程度时,它会被移动到Old Generation,最后积累一定时间再移动到Permaent Generation区域,Permaent Generation区域也存放一些静态文件。

GC回收的一些算法

Copying算法:扫描出存活的对象,并复制到一块新的完全未使用的控件中,对应于Young Generation,就是在Eden、FromSpace或ToSpace之间copy。

标记算法:扫描出存活对象,然后再回收未标记的对象,回收后对空出的空间要么合并,要么标记出来便于下次分配,以减少内存碎片带来的损耗。年老代对象存活时间较长较稳定,使用标记算法回收。

GC类型

1.kGcCauseForAlloc:在分配内存时内存不够情况下引起的GC,这种情况下GC会stop World。Stop World 是由于并发GC时,其他线程都会停止。

扫描二维码关注公众号,回复: 3165960 查看本文章

2.kGcCauseBackground:当内存达到一定阈值的时候引发GC,这个时候是一个后台GC,不会引起Stop World。

3.kGcCauseExplicit:显示调用时进行的GC,如果ART打开了这个选项,在system.gc时会进行GC。

其他GC注意事项

1.尽量不去显式调用 system.gc() 减少不必要的系统开销,影响应用的流畅度。

2.尽量减少内存泄露,避免OOM。

二、Android内存泄露

1、什么是内存泄露?

java对象有自己的生命周期,当这个对象不需要再使用时,应该完整地走完生命周期,但因为某些原因,对象虽然已经不再使用,仍然在内存中并没有结束整个生命周期,这就意味着这个对象已经泄露了。

GC会选择一些还存活的对象作为内存遍历的根节点 GC Roots,通过对GC Roots的可达性来判断是否需要回收。

Android系统虚拟机的垃圾回收是通过虚拟机GC机制来实现的。GC会选择一些存活的对象作为内存便利的跟节点GC Roots,通过判断GC Roots的可达性来判断是否需要回收,如上图其中 1 2 3 4直接或间接被GC Roots引用链相连,这类对象被认为还需要使用的对象,就不会被回收。5 6 7将会被回收。到那时这里如果Object4 如果不需要使用的话这时候也不会被回收,就属于内存泄露。

2、常见内存泄露场景以及注意事项

~ 资源型对象未关闭
~ 注册对象未注销
~ 类的静态变量持有大数据对象 如bitmap
~ 费静态内部类的静态实例
~ Handler临时性内存泄露
~ 容器中的对象没有清理造成的内存泄露

3、内存泄露分析工具

leakcanary

三、常见注意事项避免内存消耗过多

1、AutoBoxing自动装箱过程


Integer num=0;
for(int i=0;i<100;i++){
num+=i;
​​}​​

这段代码每次循环,虚拟机都必须创建一个新的整数对象,并把它加到其他整数对象前面,创建一个新的整数对象,意味着要消耗更多性能。int只有4字节,而Integer对象有16字节。

2、内容复用

1、有效利用系统自带资源。
2、视图复用,如ViewHolder。
3、对象池。
4、Bitmap对象复用。

3、使用最优的数据类型

1、当对象的数目在1000以内且特别多访问而删除和插入不高的时候尽量用ArrayMap替代HashMap。
2、枚举的最大优点是安全、易读,但是内存消耗是定义常量的三倍以上。可以使用注解方式来检查安全。
3、使用IntDef和StringDef检查类型安全。
4、LruCache建议使用这个缓存机制,但是既不能分配太大,也不能分配太小。

4、图片的内存优化

设置位图规格,使用inSampleSize实现位图缩放和压缩。使用缓存机制等。

四、内存分析工具

1、Memory Monitor

这个是一个我们开发过程中很常用的内存、CPU、网络的分析工具。
Memory Monitor界面视图
界面很直观,左上角有运行的机型和项目包名,然后最直观的动态图,分别是CPU、Memory、NetWork。点进去可以进入的Memory。
Memory Monitor的Memory局部视图
这里可以清晰的看到颜色对应区域占用的内存大小。
Memory Monitor的Memory整体视图
通过这两张图 内存的大部分信息都能查阅到。我们在操作APP加载图片等操作时候能看到内存上升、和下降,如果操作APP后发现内存不会下降可能就是我们有些对象没有及时释放,也有可能导致内存泄露。
还有对应的模拟GC,查看时间段具体内存信息以及一段时间的内存追踪等工具可以使用。可以定位到具体的代码行。如下图:
具体类详细内存信息展示
这里有一个Shallow size这个属性的概念:
Shallow size就是对象本身占用内存的大小,不包含其引用的对象。常规对象(非数组)的Shallow size有其成员变量的数量和类型决定。数组的shallow size有数组元素的类型(对象类型、基本类型)和数组长度决定。

2、Heap Viewrer

Heap Viewrer工具视图界面
如果是Android Studio的话通过Tools->Android->Android Device Monitor找到这个工具。
进入后选择运行APP的包名然后点击update Heap按钮,这时候会在每次gc时展示数据信息,也可以在后面手动GC,如果在操作页面这时候可能会发现小卡顿,因为在GC时,可能导致其他线程停止工作,这时可以清晰看到表中内存信息:
头部总览视图:

标题 含义
Heap Size 堆栈分配给APP的内存大小。
Allocated 已分配使用的内存大小。
Free 空闲的内存大小。
%Used Allocated/Heap Size 的使用率。
Object 对象数量

下面详情视图:

标题 含义
free 空闲的对象
data object 数据对象,Java类类型对象,是最主要的观察对象。
class object java类类型的引用对象。
1-byte array(byte[],boolean[]) 一字节的数组对象。
2-byte array(short[],char[]) 两字节的数组对象。
4-byte array(object[],int[],float[]) 4字节的数组对象。
8-byte array(long[],double[]) 8字节的数组对象。
non-java object 非Java对象。

每个类型的数据值对应:

标题 含义
Count 数量
Total Size 总共占用的内存的大小
Smallest 将对象占用内存从小到大排列,排在第一个对象占用内存大小
Largest 将对象占用内存从小到大排列,排在最后一个对象占用的内存大小。
Median 将对象占用内存从小到大排列,排在总监的对象占用的内存大小。
Average 平均值

猜你喜欢

转载自blog.csdn.net/xuanguofeng/article/details/78789795