简言:
我们在开发中,会很容易导致app的内存泄漏,那么什么是内存泄漏,我们要如何解决,有何进行内存泄漏的优化那?
1.什么是内存泄漏?
如果一个对象在不被需要时还在被其他对象引用,导致该对象无法被回收,导致该对象无法被释放造成空间内存的浪费,这种情况就是内存泄漏。
2.我们常见的内存泄漏有哪些那?
1) 静态变量导致的内存泄漏:
静态变量存储在方法区,它的生命周期从类加载开始到结束。一旦静态变量初始化后,它所持有的引用只有等到进程结束才会释放。
静态持有很多时候都有可能因为其使用的生命周期不一致而导致内存泄露,所以我们在新建静态持有的变量的时候需要多考虑一下各个成员之间的引用关系,并且尽量少地使用静态持有的变量,以避免发生内存泄露。当然,我们也可以在适当的时候讲静态量重置为null,使其不再持有引用,这样也可以避免内存泄露。
我们看一段代码:
public class MainActivity extends Activity{
public static Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
}
}
Context对象为静态的,那么Activity就无法正常销毁,会常驻内存。
解决办法:
使用Application的Context。 2慎用static关键字
2)非静态内部类导致内存泄露
非静态内部类默认就会持有外部类的引用,当非静态内部类对象的生命周期比外部类对象的生命周期长时,就会导致内存泄露。
Handler的使用就是典型:
handler会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,当一个对象一句不需要再使用了,本来该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏。
如何使用handler那?通过代码展示:
public class MainActivity extends AppCompatActivity{
private Handler mHandler;
@Override
protected void onCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler=newMyHandler(this);
start();
}
private void start(){
Messagemsg=Message.obtain();
msg.what=1;
mHandler.sendMessage(msg);
}
private static class MyHandler extends Handler{
private WeakReference<MainActivity> activityWeakReference;
public MyHandler(MainActivity activity){
activityWeakReference=newWeakReference<>(activity);
}
@Override
public void handleMessage(Messagemsg){
MainActivityactivity=activityWeakReference.get();
if(activity!=null){
if(msg.what==1){
//做相应逻辑
}
}
}
}
}
mHandler通过弱引用的方式持有Activity,当GC执行垃圾回收时,遇到Activity就会回收并释放所占据的内存单元。这样就不会发生内存泄露了。
3)TimerTask导致内存泄露
当我们Activity销毁的时,有可能Timer还在继续等待执行TimerTask,它持有Activity的引用不能被回收,因此当我们Activity销毁的时候要立即cancel掉Timer和TimerTask,以避免发生内存泄漏。
4)集合中的对象未清理造成内存泄露
如果一个对象放入到ArrayList、HashMap等集合中,这个集合就会持有该对象的引用。当我们不再需要这个对象时,也并没有将它从集合中移除,这样只要集合还在使用(而此对象已经无用了),这个对象就造成了内存泄露。并且如果集合被静态引用的话,集合里面那些没有用的对象更会造成内存泄露了。所以在使用集合时要及时将不用的对象从集合remove,或者clear集合,以避免内存泄漏。
5)资源未关闭或释放导致内存泄露
在使用IO、File流或者Sqlite、Cursor等资源时要及时关闭。这些资源在进行读写操作时通常都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以致发生内存泄露。因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄露。
6)属性动画造成内存泄露
动画同样是一个耗时任务,比如在Activity中启动了属性动画(ObjectAnimator),但是在销毁的时候,没有调用cancle方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用Activity,这就造成Activity无法正常释放。因此同样要在Activity销毁的时候cancel掉属性动画,避免发生内存泄漏。
总结:
内存泄露在Android内存优化是一个比较重要的一个方面。总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:
静态引用时注意应用对象的置空或者少用静态引用;
使用静态内部类+软引用代替非静态内部类;
及时取消广播或者观察者注册;耗时任务、属性动画在Activity销毁时记得cancel;
文件流、Cursor等资源及时关闭;