Android内存泄漏

本文目录

1:什么是内存泄漏

2:内存泄漏导致的问题

3:常见内存泄漏场景

(1) Handler

(2)非静态内部类

(3)Context

(4)资源对象未关闭

(5)注册对象未反注册

4.使用leakcanary

https://github.com/square/leakcanary

一:什么是内存泄漏

通俗的说:内存空间使用完毕后没有进行回收。对象在生命周期结束时,被另一个对象持有而无法释放。

在Android可以理解为生命周期长的持有了生命周期短的实例。

二:内存泄漏导致的问题

内存泄漏就是系统回收不了那些分配出去但是又不使用的内存。随着程序的运行,可以使用的内存就会变少,直到内存溢出。

三:常见内存泄漏场景

(1)使用Handler

原因:当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是处理MessageQueue中的消息。Looper的生命周期和当前应用一样长。当一个Handler在主线程进行初始化之后,我们通过Handler发送了一个消息到MessageQueue,这个消息就包含了Handler实例的引用,只有这样Looper在处理这条消息时,才会回调Handler中的handleMesage方法。在java中,非静态内部类和匿名内部类会持有外部类的引用。

当我们在Activity创建了一个匿名内部类Handler,使用Handler发送了延迟事件,当Activity销毁的时候,这个事件持有Handler的引用,如果Handler是一个匿名内部类,Handler就会持有外面Acitviy的引用。导致Activity无法被回收,从而导致内存泄漏。

解决方案:

自定义静态Handler,弱引用activity。

public class SampleActivity extends Activity {


private static class MyHandler extends Handler {

private final WeakReference<SampleActivity> mActivity;


public MyHandler(SampleActivity activity) {

mActivity = new WeakReference<SampleActivity>(activity);

}


@Override

public void handleMessage(Message msg) {

SampleActivity activity = mActivity.get();

if (activity != null) {

// ...   }}}

(2)非静态内部类持有外部类的引用

原因:内部类调用外部类,是通过一个外部类的引用进行调用的。而外部类的private属性则通过编译器生成的我们看不见的静态方法,通过传入外部类实例引用获取出来。

解决方法:使用静态内部类,静态内部类不会持有外部类的引用。当我们需要在静态内部类中调用外部的Activity时,我们可以使用弱引用处理。

(3)Context造成的内存泄漏

原因:Activity、Service、BroadcastReviver。主要是Activity,当Activity生命周期结束的时候,Activity无法被回收,导致内存泄漏。

举例:单例模式引起的内存泄漏

当我们写单例的时候,如果持有Activity的context,单例的instance作为静态对象,其生命周期要长于activity,当我们退出activity时,activity被一个单例持有,导致垃圾回收器无法进行回收,造成内存泄漏。

解决方案:使用Application的Context。

注意:不要让生命周期长于Activity的对象持有到Activity的引用

例如我们常见的dialog、menu、悬浮窗这些控件需要传入Context作为参数。如果使用Activity作为Context参数,一定要保证控件的生命周期和Activity的生命周期同步。非控件类型的对象,优先考虑使用Application的Context,避免内存泄漏。

(4)资源对象未关闭

资源性对象如Cursor、File、Socket,应该在使用后及时关闭。未在finally中关闭,会导致异常情况下资源对象未被释放的隐患。

(5)注册对象未反注册

未反注册会导致观察者列表里维持着对象的引用,阻止垃圾回收。BroadcastReciver、EventBus等。

你可能感兴趣的:(Android)