Handler内存泄漏原理和避免

内存泄漏原理

在一般情况下,我们创建Handler的时候,都是这么创建的。
标警告的Handler
贴一个百度翻译:这个Handler类应该是静态的,否则可能会发生泄漏。

就是说如果不将其设置成静态的,就会发生内存泄漏。

那么发生内存泄漏的原理是:内部非静态类会隐式的持有外部类的引用。

举一个例子:我在一个空Activity的onCreate()方法中这么写。

//在Java中,非静态内部类,可以隐性的拥有外部类的引用
Handler handler = new Handler(){
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        Log.i(TAG, "handleMessage: " + this);
        //即使在Handler内部,我也能操作MainActivity的内容
        Log.i(TAG, "handleMessage: " + MainActivity.this);
    }
};

new Thread(new Runnable() {
    @Override
    public void run() {
        handler.sendEmptyMessage(1);

    }
}).start();

运行之后结果如下:在这里插入图片描述
在这个例子中,new Handler后面花括号的就是我们的非静态匿名内部类,也是一个非静态内部类。然后在这个内部类中,我一样可以访问Activity的一切内容(比如说toString)。

Handler中对Activity的引用是强引用,强引用不会被GC回收。

然后在Activity执行onDestroy()后本来准备被系统回收,却因为内部还有一个Handler一直指向它,而导致Activity无法被回收,这就是内存泄漏了。

避免

  1. 使用弱引用来运行Handler,这样在不需要的时候,不用我们自己动手,系统就会自行的回收分配给Handler的内存,已经其中伴随着的其他外部类。
  2. 使用静态变量,使用静态变量之后,就无法持有外部类的引用了。静态变量无法持有外部类的引用

引用与GC回收机制简单介绍

GC,也就是Garbage Collection,垃圾回收机制。对于一个对象而言,如果在某一时间没有任何一个引用指向它,他就将会被回收所分配的内存。
然后是引用类型。简单来说,Java是存在引用类型的。而这个引用类型就类似于C语言的指针一样的东西。

  • 强引用:我们平时的各种声明语句就是强引用。对于GC而言,它无论如何都不会回收被强引用的对象。哪怕你哪天内存不够了,它就是给你报一个out of memory也不会回收

    Object o = new Object();
    String s;
    

    在这种情况下,如果想要回收这个Object()所分配的内存,那就只要o = null。这样如果没有任何引用指向这个实例,他就会在某一个时间被回收掉。

  • 软引用:比强引用稍微弱一点。对于GC而言,哪天如果内存不足了,他就会强制回收软引用的对象的内存。回收后还不够才会报out of memory。使用的时候一般和引用队列一起用。

    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    Object o = new Object();
    SoftReference<Object> softO = new SoftReference<>(o, referenceQueue);
    o = null;
    
  • 弱引用:比软引用更弱一点。对于GC而言,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。使用的时候一般和引用队列一起用。

    
    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    Object o = new Object();
    WeakReference<Object> weakO = new WeakReference<>(o, referenceQueue);
    o = null;
    
  • 虚引用:最弱的引用,你无法获取引用的对象(就是get()只会返回null),相当于没有引用。使用的时候必须和引用队列一起用。主要是感知对象被和系统回收的时机以采取对应的行动。

    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    Object o = new Object();
    PhantomReference<Object> phantomO = new PhantomReference<>(o, referenceQueue);
    o = null;
    

参考材料

Java四种引用类型 - CNBlog
https://www.cnblogs.com/liyutian/p/9690974.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值