美文网首页
Android 非静态内部类/匿名类/Handler引起的内存泄

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

作者: Rimson | 来源:发表于2018-10-30 17:27 被阅读0次

一、内存溢出和内存泄漏

  • 内存溢出:Android系统会给每个安卓程序分配一定的内存,当程序所使用的内存超过最大值就会造成内存溢出,就是常说的OOM(Out Of Memory)
  • 内存泄漏:例如new了一个对象,这个对象是要消耗内存的,JVM会对没有引用的对象进行回收释放内存,如果一个对象已经没有引用了,但是JVM没有回收这个对象,就会造成内存泄漏,多次内存泄漏到最后就会变成内存溢出。
    我的理解:内存溢出相当于钱用完了;但是内存泄漏是把钱借出去,虽然算起来你还是有钱的,但是当你借出去比较多而大家都不还的时候,你就相当于没钱了。

二、内存泄漏

常见的内存泄漏:

  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
            }
        }
    }
}

相关文章

  • Android常见内存泄漏

    内存泄漏场景: 静态变量引用非静态内部类/匿名类实例。子线程相关的非静态内部类/匿名内部类引用。Handler导致...

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

    一、内存溢出和内存泄漏 内存溢出:Android系统会给每个安卓程序分配一定的内存,当程序所使用的内存超过最大值就...

  • Android性能-内存泄漏

    泄漏原因: 单例造成的内存泄漏 非静态内部类(匿名类等)创建静态实例造成的内存泄漏 Handler/Thread/...

  • Android内存泄漏之集合类

    Android内存泄漏基本可以分为以下四大类:1、集合类泄漏2、单例/静态变量造成的内存泄漏3、匿名内部类/非静态...

  • Android内存优化之内存泄漏

    内存泄漏 内存泄漏一般有以下几种情况:单例、静态变量、Handler、匿名内部类、资源使用未关闭 单例导致的内存泄...

  • Java自学-接口与继承 内部类

    Java 内部类 内部类分为四种: 非静态内部类静态内部类匿名类本地类 步骤 1 : 非静态内部类 非静态内部类 ...

  • 内存泄露-问题分析

    Handler 匿名内部类、非静态内部类 如何避免 1:使用静态内部类,加上static 修饰 2:使用WeakR...

  • 关于内存泄露的知识点

    声明:内容仅限个人笔记,无参考学习价值 Handler内存泄漏及其解决方法: 1.非静态内部类,匿名内部类,都默认...

  • Android开发中的内存泄漏

    内存泄漏的几种情况 1.使用了非静态匿名内部类对象(如handler、线程) 在Activity中直接使用new ...

  • Android内存分析:profiler + MemoryAna

    一些内存泄漏的场景: 1 非静态内部类的静态实例2 多线程相关的匿名内部类/非静态内部类3 Handle内存泄漏4...

网友评论

      本文标题:Android 非静态内部类/匿名类/Handler引起的内存泄

      本文链接:https://www.haomeiwen.com/subject/nyogtqtx.html