美文网首页Android内存泄漏
内存泄漏:使用弱应用处理外部类引用

内存泄漏:使用弱应用处理外部类引用

作者: 方衍 | 来源:发表于2016-11-22 16:18 被阅读73次
public class SampleActivity extends Activity {

  /**
   * Instances of static inner classes do not hold an implicit
   * reference to their outer class.
   */
  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) {
        // ...
      }
    }
  }

  private final MyHandler mHandler = new MyHandler(this);

  /**
   * Instances of anonymous classes do not hold an implicit
   * reference to their outer class when they are "static".
   */
  private static final Runnable sRunnable = new Runnable() {
      @Override
      public void run() { /* ... */ }
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Post a message and delay its execution for 10 minutes.
    mHandler.postDelayed(sRunnable, 1000 * 60 * 10);

    // Go back to the previous Activity.
    finish();
  }
}

这里Handler为什么要用弱引用来持有Activity的引用?和使用软引用有什么区别?

这里使用弱引用持有Activity,就是表示Handler不会占用着对activity的引用而导致系统无法回收,只要系统来回收这个Activity就能回收掉。

在我的理解,使用弱引用而不是软引用,表示Handler将Activity回收权完全地交给组件管理系统:系统什么时候回收Activity我不知道,反正我不占用,只要你GC来回收时就能回收。

如果Activity被回收了,会对Handler业务逻辑有影响吗?这里需要考虑到情形。什么时候GC会来回收Activity?这时应该是用户已经退出或者跳出了这个Activity,而内存紧张,组件管理系统判断需要这个Activity了。

Handler的handleMessage()一般是在异步消息返回后更新数据操作的,这时如果Activity已经隐入后台了,一般也不再需要UI或数据的更新了。当然如果需要这个Activity常驻内存,当用户回到这个Activity可以看到更新后的数据,可以使用其他方法。

强引用

只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。

如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

软引用

软引用在Java中用java.lang.ref.SoftReference类来表示。

对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。

import java.lang.ref.SoftReference;
 
public class Main {
    public static void main(String[] args) {
         
        SoftReference<String> sr = new SoftReference<String>(new String("hello"));
        System.out.println(sr.get());
    }
}

弱引用

弱引用用java.lang.ref.WeakReference类来表示。

当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。

import java.lang.ref.WeakReference;
 
public class Main {
    public static void main(String[] args) {
     
        WeakReference<String> sr = new WeakReference<String>(new String("hello"));
         
        System.out.println(sr.get());
        System.gc(); //通知JVM的gc进行垃圾回收
        System.out.println(sr.get());
    }
}

输出结果

hello
null

第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。

虚引用

虚引用在java中用java.lang.ref.PhantomReference类表示。

虚引用并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

软引用和弱引用的区别

它们都是用来描述非必需对象的,但是被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。

引用类的使用

在SoftReference类中,有三个方法,两个构造方法和一个get方法(WekReference类似):

两个构造方法:

public SoftReference(T referent) {
    super(referent);
    this.timestamp = clock;
}
 
public SoftReference(T referent, ReferenceQueue<? super T> q) {
    super(referent, q);
    this.timestamp = clock;
}

get方法用来获取与软引用关联的对象的引用,如果该对象被回收了,则返回null。

在使用软引用和弱引用的时候,我们可以显示地通过System.gc()来通知JVM进行垃圾回收。要注意的是,虽然发出了通知,JVM不一定会立刻执行。

相关文章

  • 内存泄漏问题

    1 、非静态内部类持有外部类的引用的情况下,造成外部类在使用完成后不能被系统回收内存,从而造成内存泄漏。通过弱应用...

  • 内存泄漏:使用弱应用处理外部类引用

    这里Handler为什么要用弱引用来持有Activity的引用?和使用软引用有什么区别? 这里使用弱引用持有Act...

  • 内存泄露

    什么是内存泄漏? 引用导致的对象未被释放 引起内存泄漏的因素: 单例 非静态内部类持有外部类的隐式引用,而在外部类...

  • block的几种使用方式(学习中)

    block使用要注意使用不当,容易出现内存泄漏而崩溃,要注意判空处理,使用时尽量使用弱引用( __weak typ...

  • iOS内存管理

    使用CADisplayLink、NSTimer有什么注意点? 注意内存泄漏、循环引用的问题(self弱引用time...

  • 每日一道面试题#1 自定义 Handler 时如何有效地避免内存

    问题原因:一般非静态内部类持有外部类的引用的情况下,造成外部类在使用完成后不能被系统回收内存,从而造成内存泄漏。这...

  • Android常见内存泄漏

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

  • Android内存泄漏

    1. 内部类隐性的持有外部类的引用导致内存泄漏 private Handler Myhander=new Hand...

  • 图片加载<第四篇>:学会使用软引用解决OOM问题

    学会使用软引用和弱引用可以进一步优化内存泄漏问题。 本文主要让大家了解什么叫强引用、软引用、弱引用、虚引用以及怎么...

  • Handler内存泄漏警告处理

    Handler内存泄漏原理:非静态内部类会隐性持有外部类的引用.在Message发送过程中,引用了Handler对...

网友评论

    本文标题:内存泄漏:使用弱应用处理外部类引用

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