Java4种引用的级别由高到低依次为:
StrongReference  >  SoftReference  >  WeakReference  >  PhantomReferenceString tag = new String("T");   此处的 tag 引用就称之为强引用。而强引用有以下特征:
1. 强引用可以直接访问目标对象。
2. 强引用所指向的对象在任何时候都不会被系统回收。
3. 强引用可能导致内存泄漏。我们要讨论的其它三种Reference较之于强引用而言都属于“弱引用”,也就是他们所引用的对象只要没有强引用,就会根据条件被JVM的垃圾回收器所回收,它们被回收的时机以及用法各不相同。下面分别来进行讨论。
软引用有以下特征:
1. 软引用使用 get() 方法取得对象的强引用从而访问目标对象。
2. 软引用所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。
3. 软引用可以避免 Heap 内存不足所导致的异常。当垃圾回收器决定对其回收时,会先清空它的 SoftReference,也就是说 SoftReference 的 get() 方法将会返回 null,然后再调用对象的 finalize() 方法,并在下一轮 GC 中对其真正进行回收。
WeakReference 是弱于 SoftReference 的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get() 方法返回 null)。
弱引用有以下特征:
1. 弱引用使用 get() 方法取得对象的强引用从而访问目标对象。
2. 一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。
3. 弱引用也可以避免 Heap 内存不足所导致的异常。PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过get()方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现 get() 被重写为永远返回 null。
虚引用有以下特征:
虚引用永远无法使用 get() 方法取得对象的强引用从而访问目标对象。
虚引用所指向的对象在被系统内存回收前,虚引用自身会被放入 ReferenceQueue 对象中从而跟踪对象垃圾回收。
虚引用不会根据内存情况自动回收目标对象。
虚引用必须和引用队列(ReferenceQueue)联合使用定义一个对象Brain
public class Brain  {
    public int mIndex;
    // 占用较多内存,当系统内存不足时,会自动进行回收
    private byte []mem;
    public Brain(int index) {
        mIndex = index;
        mem = new byte[1024 * 1024];
    }
    
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        LogUtils.e("Brain", "finalize + index=" + mIndex);
    }
}创建Reference并添加到RefrenceQueue中
// 定义几个成员变量
ReferenceQueue<Brain> mWeakQueue = new ReferenceQueue<>();
ReferenceQueue<Brain> mPhQueue = new ReferenceQueue<>();
List<WeakReference<Brain>> mWeakList = new ArrayList<>();
List<PhantomReference<Brain>> mPhList = new ArrayList<>();
// 开启守护线程用于检测ReferenceQue中是否有对象被添加
private void startDemoThread() {
    Thread threadWeak = new Thread(() -> {
            try {
                int cnt = 0;
                WeakReference<Brain> k;
                // remove 方法为阻塞式的, 而poll方法不是
                while((k = (WeakReference) mWeakQueue.remove()) != null) {
                    LogUtils.e(TAG, "回收了WeakReference指向对象, : cnt=" + (cnt++) + " wf=" + k);
                }
            } catch(InterruptedException e) {
                //结束循环
            }
        }, "MainActivityWeak");
        threadWeak.setDaemon(true);
        threadWeak.start();
        Thread threadPh = new Thread(() -> {
            try {
                int cnt = 0;
                PhantomReference<Brain> k;
                while((k = (PhantomReference) mPhQueue.remove()) != null) {
                    LogUtils.e(TAG, "回收了PhantomReference指向对象, cnt=" + (cnt++) + "   pr=" + k);
                }
            } catch(InterruptedException e) {
                //结束循环
            }
        }, "MainActivityPhantom");
        threadPh.setDaemon(true);
        threadPh.start();
}
 
// 注意创建的Reference对象需要暂存起来(实测中,如果Reference被回收是不会被添加到ReferenceQueue中的)
private void test() {
    for (int i=0; i<1000; i++) {
                    Brain src1 = new Brain(i);
                    Brain src2 = new Brain(100000 + i);
                    // 将Reference注册到RefrenceQueue中
                    WeakReference<Brain> weakReference = new WeakReference<Brain>(src1, mWeakQueue);
                    mWeakList.add(weakReference);
                    
                    //将Reference注册到RefrenceQueue中
                    PhantomReference<Brain> phantomReference = new PhantomReference<>(src2, mPhQueue);
                    mPhList.add(phantomReference);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
}
    结果打印:
2019-01-29 19:22:27.499 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=0 wf=java.lang.ref.WeakReference@e1f904c
2019-01-29 19:22:27.499 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=1 wf=java.lang.ref.WeakReference@82fc895
2019-01-29 19:22:27.500 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=2 wf=java.lang.ref.WeakReference@3b3fdaa
2019-01-29 19:22:27.500 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=3 wf=java.lang.ref.WeakReference@668fd9b
2019-01-29 19:22:27.501 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=0
2019-01-29 19:22:27.501 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=100000
2019-01-29 19:22:27.502 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=4 wf=java.lang.ref.WeakReference@8db6538
2019-01-29 19:22:27.502 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=5 wf=java.lang.ref.WeakReference@f915911
2019-01-29 19:22:27.503 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=1
2019-01-29 19:22:27.503 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=100001
2019-01-29 19:22:27.504 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=2
2019-01-29 19:22:27.505 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=100002
2019-01-29 19:22:27.507 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=3
2019-01-29 19:22:27.507 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=100003
2019-01-29 19:22:27.507 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=4
2019-01-29 19:22:27.508 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=100004
2019-01-29 19:22:27.508 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=5
2019-01-29 19:22:27.509 9283-9292/com.selftest.test.testapp3 E/IFLY_SDK_Brain: finalize + index=100005
2019-01-29 19:22:27.629 9283-9309/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了PhantomReference: cnt=0   pr=null
2019-01-29 19:22:27.629 9283-9309/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了PhantomReference: cnt=1   pr=null
2019-01-29 19:22:27.629 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=6 wf=java.lang.ref.WeakReference@e2c4a76
2019-01-29 19:22:27.630 9283-9309/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了PhantomReference: cnt=2   pr=null
2019-01-29 19:22:27.630 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=7 wf=java.lang.ref.WeakReference@4cfd877
2019-01-29 19:22:27.630 9283-9309/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了PhantomReference: cnt=3   pr=null
2019-01-29 19:22:27.630 9283-9309/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了PhantomReference: cnt=4   pr=null
2019-01-29 19:22:27.630 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=8 wf=java.lang.ref.WeakReference@37d9ce4
2019-01-29 19:22:27.630 9283-9309/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了PhantomReference: cnt=5   pr=null
2019-01-29 19:22:27.630 9283-9308/com.selftest.test.testapp3 E/IFLY_SDK_MainActivity: 回收了WeakReference: cnt=9 wf=java.lang.ref.WeakReference@ea1754d结果分析:
LeakCanery是Android检测内存泄漏的工具,可以检测到Activity/Fragment存在的内存泄漏。
检测原理:
//ActivityRefWatcher 中的代码
public void watchActivities() {
    // Make sure you don't get installed twice.
    stopWatchingActivities();
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
  }
  public void stopWatchingActivities() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
  }private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new ActivityLifecycleCallbacksAdapter() {
        @Override public void onActivityDestroyed(Activity activity) {
          refWatcher.watch(activity);
        }
      };具体的watch执行如下:
public void watch(Object watchedReference, String referenceName) {
    if (this == DISABLED) {
      return;
    }
    checkNotNull(watchedReference, "watchedReference");
    checkNotNull(referenceName, "referenceName");
    final long watchStartNanoTime = System.nanoTime();
    String key = UUID.randomUUID().toString();
    retainedKeys.add(key);
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);
    ensureGoneAsync(watchStartNanoTime, reference);
  }ensureGoneAsync执行如下:
// watchExecutor 在一定时间后检查被注册的WeakReference有没有被添加到ReferenceQueue中
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
    watchExecutor.execute(new Retryable() {
      @Override public Retryable.Result run() {
        return ensureGone(reference, watchStartNanoTime);
      }
    });
  }long gcStartNanoTime = System.nanoTime();
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
    // 如果ReferenceQue中有activity的弱引用,则将retainedKeys中的uuid移除
    removeWeaklyReachableReferences();
    if (debuggerControl.isDebuggerAttached()) {
      // The debugger can create false leaks.
      return RETRY;
    }
    
    // 如果activity对应的uuid已经被移除,说明activity已经被回收,无内存泄漏
    if (gone(reference)) {
      return DONE;
    }
    
    // 触发gc,进行垃圾回收
    gcTrigger.runGc();
    removeWeaklyReachableReferences();
    
    // 如果uuid还没有被移除,说明activiy存在内存泄漏,需要dump内存,进行分析
    if (!gone(reference)) {
      long startDumpHeap = System.nanoTime();
      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
      File heapDumpFile = heapDumper.dumpHeap();
      if (heapDumpFile == RETRY_LATER) {
        // Could not dump the heap.
        return RETRY;
      }
      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
      HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
          .referenceName(reference.name)
          .watchDurationMs(watchDurationMs)
          .gcDurationMs(gcDurationMs)
          .heapDumpDurationMs(heapDumpDurationMs)
          .build();
      heapdumpListener.analyze(heapDump);
    }
    return DONE;
  }HeapDump dump内存和分析的过程这里就不细说。
原文:https://www.cnblogs.com/NeilZhang/p/11441402.html