美文网首页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不一定会立刻执行。

    相关文章

      网友评论

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

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