LeakCanary原理分析

 

LeakCanary


class Helper {
}

class Utils {
  public static Helper helper = new Helper();
}

static Helper helper = new Helper

class ExampleApplication : Application() {
  val leakedViews = mutableListOf<View>()
}

class MainActivity : Activity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)

    val textView = findViewById<View>(R.id.helper_text)

    val app = application as ExampleApplication
    // This creates a leak, What a Terrible Failure!
    app.leakedViews.add(textView)
  }
}


ExampleApplication :Application
app.leakedViews.add(textView);

AppWatcher.Config config = AppWatcher.getConfig().newBuilder()
   .watchFragmentViews(false)
   .build();
AppWatcher.setConfig(config);

LeakCanary.Config config = LeakCanary.getConfig().newBuilder()
   .retainedVisibleThreshold(3)
   .build();
LeakCanary.setConfig(config);


.watchFragmentViews    .retainedVisibleThreshold            .build

class DebugExampleApplication : ExampleApplication() {

  override fun onCreate() {
    super.onCreate()
    LeakCanary.config = LeakCanary.config.copy(onHeapAnalyzedListener = LeakUploader())
  }
}


LeakCanary.config = LeakCanary.config.copy onHeapAnalyzedListener = LeakUploader


https://square.github.io/leakcanary/recipes/


class MyService : Service {

  // ...

  override fun onDestroy() {
    super.onDestroy()
    AppWatcher.objectWatcher.watch(
      watchedObject = this,
      description = "MyService received Service#onDestroy() callback"
    )
  }
}

AppWatcher.objectWatcher.watch (

    watchob = this;
    
    description = "";

);


./gradlew leakcanary-android-sample:connectedCheck


./gradlew leakcanary-android-sample:connectedCheck

class DebugExampleApplication : ExampleApplication() {

  override fun onCreate() {
    super.onCreate()
    LeakCanary.config = LeakCanary.config.copy(
        referenceMatchers = AndroidReferenceMatchers.appDefaults +
            AndroidReferenceMatchers.staticFieldLeak(
                className = "com.samsing.SomeSingleton",
                fieldName = "sContext",
                description = "SomeSingleton has a static field leaking a context.",
                patternApplies = {
                  manufacturer == "Samsing" && sdkInt == 26
                }
            )
    )
  }
}

DebugExampleApplication ExampleApplication 

LeakCanary referenceMatchers = AndroidReferenceMatchers    staticFieldLeak )

patternApplies 

class DebugExampleApplication : ExampleApplication() {

  companion object {
    @JvmStatic
    lateinit var savedVersionName: String
  }

  override fun onCreate() {
    super.onCreate()

    val packageInfo = packageManager.getPackageInfo(packageName, 0)
    savedVersionName = packageInfo.versionName

    LeakCanary.config = LeakCanary.config.copy(
        metadataExtractor = MetadataExtractor { graph ->
          val companionClass =
            graph.findClassByName("com.example.DebugExampleApplication")!!

          val versionNameField = companionClass["savedVersionName"]!!
          val versionName = versionNameField.valueAsInstance!!.readAsJavaString()!!

          val defaultMetadata = AndroidMetadataExtractor.extractMetadata(graph)

          mapOf("App Version Name" to versionName) + defaultMetadata
        })
  }
}

LeakCanary原理解析
https://www.jianshu.com/p/261e70f3083f


   refWatcher = LeakCanary.install(this)

   DebuggerControl debuggerControl = this.debuggerControl;
    if (debuggerControl == null) {
      debuggerControl = defaultDebuggerControl();
    }

    HeapDumper heapDumper = this.heapDumper;
    if (heapDumper == null) {
      heapDumper = defaultHeapDumper();
    }

    WatchExecutor watchExecutor = this.watchExecutor;
    if (watchExecutor == null) {
      watchExecutor = defaultWatchExecutor();
    }

    GcTrigger gcTrigger = this.gcTrigger;
    if (gcTrigger == null) {
      gcTrigger = defaultGcTrigger();
    }


  String mainProcess = packageInfo.applicationInfo.processName;
  
  
   public RefWatcher buildAndInstall() {
    if (LeakCanaryInternals.installedRefWatcher != null) {
      throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
    }
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
      if (watchActivities) {
        ActivityRefWatcher.install(context, refWatcher);
      }
      if (watchFragments) {
        FragmentRefWatcher.Helper.install(context, refWatcher);
      }
    }
    LeakCanaryInternals.installedRefWatcher = refWatcher;
    return refWatcher;
  }

 ReferenceQueue<Activity> mQueue = new ReferenceQueue<>();
 WeakReference<Activity> mWeakReference = new WeakReference<Activity>(mActivity,mQueue);


csdn

LeakCanary实现内存泄漏的主要判断逻辑是这样的。当我们观察的Activity或者Fragment销毁时,我们会使用一个弱引用去包装当前销毁的Activity或者Fragment,并且将它与本地的一个ReferenceQueue队列关联。我们知道如果GC触发了,系统会将当前的引用对象存入队列中。
如果没有被回收,队列中则没有当前的引用对象。所以LeakCanary会去判断,ReferenceQueue是否有当前观察的Activity或者Fragment的引用对象,第一次判断如果不存在,就去手动触发一次GC,然后做第二次判断,如果还是不存在,则表明出现了内存泄漏。

public class WeakReference<T> extends Reference<T> {
    public WeakReference(T referent) {
        super(referent);
    }

    
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

    RefWatcher refWatcher = build();

return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
        heapDumpBuilder);

  queue = new ReferenceQueue<>();


  private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new ActivityLifecycleCallbacksAdapter() {
        @Override public void onActivityDestroyed(Activity activity) {
          refWatcher.watch(activity);
        }
      };
      
        public void watch(Object watchedReference) {
    watch(watchedReference, "");
  }

      
      final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);

WeakReference RefWatcher

        
      install    install                        buildAndInstall
      

 private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
      new FragmentManager.FragmentLifecycleCallbacks() {
        @Override
        public void onFragmentDestroyed(FragmentManager fm, Fragment fragment) {
          refWatcher.watch(fragment);
        }
      };


onFragmentDestroyed KeyedWeakReference 

static void add(Reference<?> list) {
        synchronized (ReferenceQueue.class) {
            if (unenqueued == null) {
                unenqueued = list;
            } else {
                // Find the last element in unenqueued.
                Reference<?> last = unenqueued;
                while (last.pendingNext != unenqueued) {
                  last = last.pendingNext;
                }
                // Add our list to the end. Update the pendingNext to point back to enqueued.
                last.pendingNext = list;
                last = list;
                while (last.pendingNext != list) {
                    last = last.pendingNext;
                }
                last.pendingNext = unenqueued;
            }
            ReferenceQueue.class.notifyAll();
        }
    }

last.pendingNext = list      
last = list

synchronized void enqueue(Reference<? extends T> reference) {
        if (tail == null) {
            head = reference;
        } else {
            tail.queueNext = reference;
        }

        // The newly enqueued reference becomes the new tail, and always
        // points to itself.
        tail = reference;
        tail.queueNext = reference;
        notify();
    }

enqueue

tail.queueNext = reference

Reference


final class KeyedWeakReference extends WeakReference<Object> {
  public final String key;
  public final String name;

  KeyedWeakReference(Object referent, String key, String name,
      ReferenceQueue<Object> referenceQueue) {
    super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));
    this.key = checkNotNull(key, "key");
    this.name = checkNotNull(name, "name");
  }
}

 public WeakReference(T r, ReferenceQueue<? super T> q) {
        super(r, q);
    }

WeakReference

install    constructor = newinstance
application.registerActivityLifecycleCallbacks(helper.activityLifecycleCallbacks)


  @Override public void execute(Retryable retryable) {
    if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
      waitForIdle(retryable, 0);
    } else {
      postWaitForIdle(retryable, 0);
    }
  }


 public final RefWatcher build() {
    if (isDisabled()) {
      return RefWatcher.DISABLED;
    }

    if (heapDumpBuilder.excludedRefs == null) {
      heapDumpBuilder.excludedRefs(defaultExcludedRefs());
    }

    HeapDump.Listener heapDumpListener = this.heapDumpListener;
    if (heapDumpListener == null) {
      heapDumpListener = defaultHeapDumpListener();
    }

    DebuggerControl debuggerControl = this.debuggerControl;
    if (debuggerControl == null) {
      debuggerControl = defaultDebuggerControl();
    }

    HeapDumper heapDumper = this.heapDumper;
    if (heapDumper == null) {
     //调用的是AndroidRefWatcherBuilder中的方法。所以这里创建的是一个AndroidHeapDumper对象
      heapDumper = defaultHeapDumper();
    }

    WatchExecutor watchExecutor = this.watchExecutor;
    if (watchExecutor == null) {
      //调用的是AndroidRefWatcherBuilder中的方法。所以这里创建的是一个AndroidWatchExecutor对象
      watchExecutor = defaultWatchExecutor();
    }

    GcTrigger gcTrigger = this.gcTrigger;
    if (gcTrigger == null) {
      //创建的是GcTrigger DEFAULT这个对象
      gcTrigger = defaultGcTrigger();
    }

    if (heapDumpBuilder.reachabilityInspectorClasses == null) {
      heapDumpBuilder.reachabilityInspectorClasses(defaultReachabilityInspectorClasses());
    }

    return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
        heapDumpBuilder);
  }

HeapDump  DebuggerControl WatchExecutor GcTrigger


RefWatcher

  public void watch(Object watchedReference, String referenceName) {
  
  
  retainKeys.add(key);

Support
  // AndroidOFragmentRefWatcher
private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
    new FragmentManager.FragmentLifecycleCallbacks() {
      @Override public void onFragmentViewDestroyed(FragmentManager fm, Fragment fragment) {
        View view = fragment.getView();
        if (view != null) {
          refWatcher.watch(view);
        }
      }
      @Override
      public void onFragmentDestroyed(FragmentManager fm, Fragment fragment) {
        refWatcher.watch(fragment);
      }
    };

@Override public void watchFragments(Activity activity) {
  FragmentManager fragmentManager = activity.getFragmentManager();
  fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true);
}

onFragmentViewDestroyed     onFragmentDestroyed

RefWatcher WatchExecutor DebuggerControl GcTrigger 


HeapDump retainKeys ReferenceQueue

RefWatcher: 核心类,负责管理和提供入口watch(),由AndroidRefWatcherBuilder创建RefWatcher,建造者模式

WatchExecutor: 负责控制执行检测内存泄漏任务

DebuggerControl:判断是否处于debug

GcTrigger:负责触发一次GC

HeapDump:表示指定时刻的堆栈的快照,AndroidHeapDump为子类

HeapDump.Builder: 负责创建HeapDump

HeapDump.Listener:监听器,当发生内存泄漏的时候,会收到消息,需要触发分析AndroidHeapDump任务

ServiceHeapDumpListener:HeapDump.Listener的实现类,当触发分析任务,调用HeapAnalyzerService执行分析任务

HeapAnalyzerService:是一个Android中四大组件之一的Service,运行在独立的进程,负责执行分析任务和UI通知

HeapAnalyzer:在HeapAnalyzerService内部中,是对DumpHeap分析内存泄漏和找出引用链的工具

retainKeys: 是一个Set,保存着当前还没被回收的Reference的key

ReferenceQueue:引用队列,WeakReference可以关联引用队列,当reference被回收时,会被加入到ReferenceQueue,这样我们就可以判断哪些对象没有被回收了

DisplayLeakService:记录泄漏日志和展示通知的Service

其实,leakCanary的基本原理就是利用ReferenceQueue,在Activity销毁的时候判断对象有没有被加入ReferenceQueue,若没有则说明Activity还在存活,可能存在泄漏。

RefWatcher     WatchExecutor DebuggerControl GcTrigger HeapDump

HeapDump.Builder      HeapDump.Listener 

ServiceHeapDumpListener:HeapDump        

HeapAnalyzerService:是一个Android中四大组件之一的Service,运行在独立的进程,负责执行分析任务和UI通知

retainKeys  ReferenceQueue        DisplayLeakService:记录泄漏日志和展示通知的Service


AndroidHeapDumper为子类


AndroidDebuggerControl

ActivityRefWatcher.install 

FragmentRefWatcher.install


removeWeakly 

// RefWatcher
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
  long gcStartNanoTime = System.nanoTime();
  long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);

  // 1. 从retainedKeys移除掉已经被会回收的弱引用的key
  removeWeaklyReachableReferences();

 // 2. 如果是debug模式,会继续重试
  if (debuggerControl.isDebuggerAttached()) {
    // The debugger can create false leaks.
    return RETRY;
  }

 // 3. 若当前引用不在retainedKeys,说明不存在内存泄漏
  if (gone(reference)) {
    return DONE;
  }

 // 4. 触发一次gc
  gcTrigger.runGc();

 // 5.再次从retainedKeys移除掉已经被会回收的弱引用的key
removeWeaklyReachableReferences();

  if (!gone(reference)) {
   // 存在内存泄漏
    long startDumpHeap = System.nanoTime();
    long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
   
   // 6. 创建heapDump文件,还没写入
    File heapDumpFile = heapDumper.dumpHeap();
    if (heapDumpFile == RETRY_LATER) {
      // Could not dump the heap.
      return RETRY;
    }
    long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
    // 7. 创建heapDump
    HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
        .referenceName(reference.name)
        .watchDurationMs(watchDurationMs)
        .gcDurationMs(gcDurationMs)
        .heapDumpDurationMs(heapDumpDurationMs)
        .build();
    // 8.调用heapdumpListener分析
    heapdumpListener.analyze(heapDump);
  }
  return DONE;
}

private boolean gone(KeyedWeakReference reference) {
  return !retainedKeys.contains(reference.key);
}

private void removeWeaklyReachableReferences() {
  KeyedWeakReference ref;
  while ((ref = (KeyedWeakReference) queue.poll()) != null) {
    retainedKeys.remove(ref.key);
  }
}


removeWeaklyReachableReferences gone 


gcTrigger.runGc


// RefWatcher
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
  long gcStartNanoTime = System.nanoTime();
  long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);

  // 1. 从retainedKeys移除掉已经被会回收的弱引用的key
  removeWeaklyReachableReferences();

 // 2. 如果是debug模式,会继续重试
  if (debuggerControl.isDebuggerAttached()) {
    // The debugger can create false leaks.
    return RETRY;
  }

 // 3. 若当前引用不在retainedKeys,说明不存在内存泄漏
  if (gone(reference)) {
    return DONE;
  }

 // 4. 触发一次gc
  gcTrigger.runGc();

 // 5.再次从retainedKeys移除掉已经被会回收的弱引用的key
removeWeaklyReachableReferences();

  if (!gone(reference)) {
   // 存在内存泄漏
    long startDumpHeap = System.nanoTime();
    long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
   
   // 6. 创建heapDump文件,还没写入
    File heapDumpFile = heapDumper.dumpHeap();
    if (heapDumpFile == RETRY_LATER) {
      // Could not dump the heap.
      return RETRY;
    }
    long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
    // 7. 创建heapDump
    HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
        .referenceName(reference.name)
        .watchDurationMs(watchDurationMs)
        .gcDurationMs(gcDurationMs)
        .heapDumpDurationMs(heapDumpDurationMs)
        .build();
    // 8.调用heapdumpListener分析
    heapdumpListener.analyze(heapDump);
  }
  return DONE;
}

private boolean gone(KeyedWeakReference reference) {
  return !retainedKeys.contains(reference.key);
}

gcTrigger之后 KeyedWeakReference(弱引用)消失,ref还在
private void removeWeaklyReachableReferences() {
  KeyedWeakReference ref;
  while ((ref = (KeyedWeakReference) queue.poll()) != null) {
    retainedKeys.remove(ref.key);
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值