Android性能优化解决方案

Android开发做久了,你会发现很多APP出现内存泄漏,卡顿,加载迟缓等问题,这时你会细细体味出这样的APP其实很一般,这说明我们也走向深度开发中,技术实力也提高了很大一部分,以下是我常见的一些内存泄漏问题以及优化方案.

一,内存泄漏

内存泄漏是指由于代码编写不当导致不再使用的对象无法得到及时释放。内存泄漏产生的内存垃圾不仅浪费资源,拖慢运行效率,甚至还可能造成内存溢出,直接导致应用崩溃。

对于Android应用,比较容易发生泄漏的是Activity、Fragment对象,此类对象的共性是其都有一定的生命周期。以Activity为例,一个Activity实例的生命起始于onCreate(),终结于onDestroy()。当一个Activity不再使用时,系统会调用回调方法Activity.onDestroy()方法做一些清理操作。但是对于Activity对象本身所占内存,则完全由虚拟机的垃圾回收器来完成回收。垃圾回收器会检查该实例是否被持有强引用,如果存在指向该对象的强引用,则不会回收其所占内存空间,这块内存空间也就成了内存垃圾。由此可见内存泄漏是由不当的强引用导致的。

1.1 对象的引用链

从GC ROOT到泄漏对象的引用链能精准地定位导致内存泄漏的原因。对象无法被垃圾回收器回收,一定是由于GC ROOT直接或间接持有了它的强引用。

常见的GCROOT有:声明为static的变量,未停止的线程,Application对象,甚至是栈内存中的局部变量。

**1.2 Android中常见的内存泄露
a.集合中对象没清理造成的内存泄露**

编程过程中,我们常常会把一些对象加入到集合中。在我们不再需要该对象时,如果没有及时把它从集合中清理掉,就会导致这个集合占用的内存越来越大。同时如果这个集合是静态的话,那情况就更严重了。如下的代码段中在每次启动Activity的时候都往静态集合中添加了一个对象,如果Activity被频繁启动,set将不断变大,影响APP的正常运行。

这里写图片描述

所以,集合中不再使用的对象应及时释放掉。上述代码应该在Activity的onDestroy()方法中,及时清理set里的元素,避免无用对象继续存在强引用,例如:

这里写图片描述

这样可以保证set持有的强引用都被释放。

单例的静态特性使得其生命周期可能跟应用的生命周期一样长,如果使用不恰当的话,很容易造成内存泄漏。

如下代码是一个简单的单例模式实现:

b. 单例模式造成的内存泄漏

在创建单例的时候,如果我们传入当前Activity的Context,例如:

这里写图片描述

单例testContextHelper里面一直保存着该Activity的引用,当这个Context 对应的 Activity 退出时,由于该 Context 的引用一直被单例对象持有,所以该Activity占用的内存并不会被回收,造成泄漏。在使用单例模式时,一定要避免持有短生命周期对象的引用,比如上述代码在引用Context时可以使用Application的Context代替Activity的Context,即:

这里写图片描述

因为Application在应用的运行过程中一直存在,不会退出。

c. 非静态内部类创建静态实例造成的内存泄漏

在启动频繁的Activity中,为了避免反复创建某些资源,提高加载速度,我们可能会在Activity内部创建一个静态实例,每次启动Activity时都会使用该实例,如下代码:

这里写图片描述

此时Activity内部有一个静态单例,且为非静态内部类的实例。由于非静态内部类默认会持有外部类的引用,并且该类创建了一个静态实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。为了避免这一问题,在使用过程中,正确的做法是将内部类设为静态类或者变成单独的类。

d. 使用handler时的内存问题

在Android应用中,Handler通过发送Message与其他线程交互,发出的Message被存储在目标线程的MessageQueue中的,并且Message不一定马上就被处理,驻留时间可能比较久。比如我们用Handler发送一个延时比较久的Message:

这里写图片描述

而Message中持有Handler实例的强引用,如果Message在Queue中一直存在,就会导致Handler实例无法被回收,而Handler持有Activity的强引用,Activity对象也不会被回收,这就造成了实例泄露。所以,在创建Handler时,最好使用弱引用来引用目标Activity对象,比如:

这里写图片描述

这样可以避免由于Handler持有强引用导致Activity无法回收。
e. 静态成员变量造成的内存泄露

如果成员变量被声明为 static,其生命周期将与整个应用进程的生命周期一样。如果静态变量直接或间接强引用了某一短生命周期对象(比如Activity),这会导致即使app切到后台,这部分内存也不会被释放。下面的错误示范代码中,在Activity启动的时候,直接将其引用赋给了静态变量obj,会导致该Activity一直不能被回收,导致内存泄露。

因此,在使用静态变量时,应该避免其持有短生命周期对象的强引用,可以使用弱引用来代替强引用。

f. 资源未关闭造成的内存泄漏

对于使用了BroadcastReceiver,ContentObserver,File,游标Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将可能不会被回收,造成内存泄漏。虽然有些系统程序,它本身可以自动取消注册的(非即时),但是我们还是应该在我们的程序中明确的取消注册,程序结束时应该把所有的注册都取消掉。

以上就是常见的性能优化方法,至于最简单的布局优化,我就不一一介绍了,这些都要你自己去解决,当然了还需要会利用常见的优化工具,
列如:
MQC http://mqc.yunos.com/alert.htm
MAT等等,只要会使用一种工具就可以分析问题了,再次如有什么问题,我们一起交流,解决!

这里写图片描述

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值