Android 非静态内部类/匿名类/Handler引起的内存泄

2018-10-30  本文已影响0人  Rimson

一、内存溢出和内存泄漏

二、内存泄漏

常见的内存泄漏:

  1. 非静态内部类/匿名内部类的静态实例容易造成内存泄漏
  2. 单例模式导致的内存泄漏
  3. 对该解注册、注销、清空的对象没有及时做这样操作导致的,比如说广播、服务、IO流等等。(其实我个人觉得这一条的最终原因还是第一条,因为说到底还是引用没有释放使JVM没有不能回收)

三、举个例子

public class MainActivity extends AppCompatActivity {
    private static Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        context=this;

    }
}

此时static会警告:

Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run) less... (Ctrl+F1)
A static field will leak contexts. Non-static inner classes have an implicit reference to their outer class. If that outer class is for example a Fragment or Activity, then this reference means that the long-running handler/loader/task will hold a reference to the activity which prevents it from getting garbage collected. Similarly, direct field references to activities and fragments from these longer running instances can cause leaks. ViewModel classes should never point to Views or non-application Contexts. Issue id: StaticFieldLeak

被static修饰的Context是持有MainActivity的引用的,它的生命周期是超过MainActivity的,并且这个本该被回收的Activty由于它还一直存在着,这就导致了内存泄漏。

四、对于Handler

public class MainActivity extends AppCompatActivity {
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //TODO
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handler.sendMessage(new Message());
    }
}

Handler的生命周期与Activity不一致,非静态(匿名)内部类会默认隐性引用外部类对象,所以Handler对Activity的引用阻止了GC对Activity的回收。

解决方法

自定义静态类继承自Handler,静态类不持有外部类的对象,所以Activity可以随意被回收。
但是使用了以上方法之后,由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference),GC回收的时候会忽略弱引用。

public class MainActivity extends AppCompatActivity {
    private Handler handler=new TestHandler(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handler.sendMessage(new Message());
    }

    static class TestHandler extends Handler{
        WeakReference<Activity> mActivityReference;

        TestHandler(Activity activity){
            mActivityReference=new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            final Activity activity=mActivityReference.get();
            if (activity!=null){
                //TODO
            }
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读