第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

LeakCanary源碼淺析

標(biāo)簽:
Android

在Android开发中最让人们头疼的就是内存泄漏了,今天来介绍一个查看内存是否泄漏的工具LeakCanary,并通过研究源码明白它是如何分析和查找存在泄漏信息的

在Android开发中最让人们头疼的就是内存泄漏了,今天来介绍一个查看内存是否泄漏的工具LeakCanary,并通过研究源码明白它是如何分析和查找存在泄漏信息的
首先送上LeakCanary文档链接:LeakCanary中文使用说明

Part1. 知识回顾

常用工具

  1. Mat


  1. LeakCanary(Square) 
    原理:watch监视一个即将要销毁的对象

内存种类
  • 1、栈(stack-基本数据类型,对象的引用)

  • 2、堆(heap-存放new出来的对象和数组,在堆中分配内存由GC管理)

  • 3、方法区(method,大体和堆一样)

为什么会产生内存泄漏
  • 当一个对象已经不需要再使用了,在该对象被回收时候,有另外的对象引用该回收对象,导致本该被回收的对象无法回收

  • 有些对象只有有限的生命周期,当生命周期很短的完成任务后,在本该结束的生命周期中仍然被引用

内存泄漏会导致什么问题
  1. OOM

常见的内存泄漏情况
  1. 单例造成的内存泄漏

  2. 非静态内部类创建静态实例造成的内存泄漏

  3. handler造成内存泄漏(handler、message、MessageQueue)
    解决方法:

        ①将Handler声明为静态类型    
        ②通过弱引用的方式引入Activity
  4. 线程造成的内存泄漏(解决方法:将线程定义声明为static类型)

  5. webview造成的内存泄漏(example:加载页面很复杂,Ex:大量的图片)

Part2 概念

引用类型
  1. 强引用(StrongReference),默认对象一般为强引用

  2. 软引用(SoftReference),当内存空间足够大时相当于强引用,内存不够时通过垃圾回收器(GC)自动回收

  3. 弱引用(WeakReference),当GC扫描到该类型的引用时就自己回收

  4. 虚引用,相当于没有进行引用,GC可随时回收该类型的引用

ReferenceQueue
  1. 软引用和弱引用都持有该对象

  2. 对象被垃圾回收,Java虚拟机就会把这个引用加入到与之相关联的引用队列中

Part3.LeakCanary使用

  1. 在module层级中的build.gradle中加入引用,不同的编译使用不同的引用

dependencies {
    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'}

2.在Application中:

public class MyApplication extends Application {    @Override
    public void onCreate() {        super.onCreate();
        LeakCanary.install(this);
    }
}

3.在Manifest.xml中加载该Application文件

<application android:name=".MyApplication">

Part4. LeakCanary源码剖析

从代码入口剖析:

 LeakCanary.install(this);

跟踪源码可知

/**
   * Creates a {@link RefWatcher} that works out of the box, and starts watching activity
   * references (on ICS+).
   */
  public static RefWatcher install(Application application) {    return install(application, DisplayLeakService.class);
  }

从上面的代码我们发现这个方法最终返回给我们一个RefWatcher这个类,这个类是主要是启动ActivityRefWatcher类,ActivityRefWatcher在Activity的onDestory方法结束时检测内存泄漏。

看下install这个方法:

/**
   * Creates a {@link RefWatcher} that reports results to the provided service, and starts watching
   * activity references (on ICS+).
   */
  public static RefWatcher install(Application application,      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {    if (isInAnalyzerProcess(application)) {      return RefWatcher.DISABLED;
    }
    enableDisplayLeakActivity(application);
    HeapDump.Listener heapDumpListener =        new ServiceHeapDumpListener(application, listenerServiceClass);
    RefWatcher refWatcher = androidWatcher(application, heapDumpListener);
    ActivityRefWatcher.installOnIcsPlus(application, refWatcher);    return refWatcher;
  }

通过 RefWatcher refWatcher = androidWatcher(application, heapDumpListener)创建一个RefWatcher对象,启动activityRefWatcher来监视内存泄漏
 enableDisplayLeakActivity(application)主要作用是开启DisplayLeakActivity这个类,这个类主要是显示内存泄漏的弹框页面

ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {    if (SDK_INT < ICE_CREAM_SANDWICH) {      // If you need to support Android < ICS, override onDestroy() in your base activity.
      return;
    }
    ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
    activityRefWatcher.watchActivities();
  } public void watchActivities() {    // Make sure you don't get installed twice.
    stopWatchingActivities();
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
  }  public void stopWatchingActivities() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
  }

小结: 
①通过stopWatcher方法反注册以前的Activity的生命周期的callback,目的是为了保证以前的内存泄漏的activity删除
②重新注册activity生命周期的callback 
③通过lifecycleCallbacks中的onActivityDestroyed方法将activity的生命周期和ActivityReference关联起来

 @Override 
  public void onActivityDestroyed(Activity activity) {
     ActivityRefWatcher.this.onActivityDestroyed(activity);
        }

跟踪onActivityDestroyed方法发现通过调用RefWatcher调用了watcher类

void onActivityDestroyed(Activity activity) {
    refWatcher.watch(activity);
  }
  private final RefWatcher refWatcher

下面我们进入RefWatcher类中发现有如下的变量信息

  private final Executor watchExecutor;  private final DebuggerControl debuggerControl;  private final GcTrigger gcTrigger;  private final HeapDumper heapDumper;  private final Set<String> retainedKeys;  private final ReferenceQueue<Object> queue;  private final HeapDump.Listener heapdumpListener;

上述变量大意如下:

  1. watchExecutor主要用于执行内存泄漏检测

  2. debuggerControl查询我们是否正在调试中,如果我们正在调试过程中则不会进行判断

  3. gcTrigger用于处理GC,用于在判断泄漏对象之前再调用GC类中的方法再次判断

  4. heapDumper用于dump中内存泄漏堆文件

  5. retainedKeys该set集合持有待检测和已产生内存泄漏信息的key

  6. queue引用对象,主要是判断弱引用所持有的对象是否已执行GC垃圾收回

  7. heapdumpListener主要用于分析产生hprof文件回调

查看watch方法可知:

    /**
   * Watches the provided references and checks if it can be GCed. This method is non blocking,
   * the check is done on the {@link Executor} this {@link RefWatcher} has been constructed with.
   *
   * @param referenceName An logical identifier for the watched object.
   */
  public void watch(Object watchedReference, String referenceName) {
    checkNotNull(watchedReference, "watchedReference");
    checkNotNull(referenceName, "referenceName");    if (debuggerControl.isDebuggerAttached()) {      return;
    }    final long watchStartNanoTime = System.nanoTime();
    String key = UUID.randomUUID().toString();
    retainedKeys.add(key);    final KeyedWeakReference reference =        new KeyedWeakReference(watchedReference, key, referenceName, queue);
    watchExecutor.execute(new Runnable() {      @Override public void run() {
        ensureGone(reference, watchStartNanoTime);
      }
    });
  }

通过产生一个唯一的key添加到retainedKeys<Set>集合中

String key = UUID.randomUUID().toString();
retainedKeys.add(key);

再创建一个KeyedWeakReference的弱引用,并开启一个异步线程来分析创建好的弱引用,该线程主要作用是确保我们的Activity是否真正已经进入到GONE状态

void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {    long gcStartNanoTime = System.nanoTime(); 
    //计算过去的方法到调用GC垃圾收回的时间值
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);    //清除已经到达我们引用队列的弱引用
    removeWeaklyReachableReferences();    //判断如果处于debug状态就不再进行内存分析
    if (gone(reference) || debuggerControl.isDebuggerAttached()) {      return;
    }
    gcTrigger.runGc();//手动进行垃圾回收
    removeWeaklyReachableReferences();    if (!gone(reference)) {      long startDumpHeap = System.nanoTime();      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
      File heapDumpFile = heapDumper.dumpHeap();//dump出内存泄漏的文件
      if (heapDumpFile == null) {        // Could not dump the heap, abort.
        return;
      }      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);      //开始分析内存泄漏文件查找内存泄漏路径
      heapdumpListener.analyze(          new HeapDump(heapDumpFile, reference.key, reference.name, watchDurationMs, gcDurationMs,
              heapDumpDurationMs));
    }
  }

以上代码部分总结如下:

  1. 首先创建一个RefWatcher,启动一个ActivityRefWatcher

  2. 通过ActivityLifecyclecallback将Activity的onDestroy生命周期给关联起来

  3. 最后通过执行execute线程来分析泄漏信息

探讨LeakCanary中Activity泄漏检测机制代码

在上面的ensureGone方法中最后我们发现有这样的代码

heapdumpListener.analyze(          new HeapDump(heapDumpFile, reference.key, reference.name, watchDurationMs, gcDurationMs,
              heapDumpDurationMs));
    }

通过跟踪发现analyze方法该方法是HeapDump类中的一个interface接口,再查看它的实现类发现在ServiceHeapDumpListener这个类中的方法

      @Override public void analyze(HeapDump heapDump) {
    checkNotNull(heapDump, "heapDump");
    HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
  }

继续跟踪runAnalysis方法发现在HeapAnalyzerService中,且该类继承了intentService,因此它将会每次调用onHandleIntent方法

  @Override 
  protected void onHandleIntent(Intent intent) {
    String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA);
    HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);
    AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey);
    AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
  }
通过checkForLeak方法来分析内存泄漏信息的结果,并通过sendResultToListener显示最终的结果public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {    long analysisStartNanoTime = System.nanoTime();    if (!heapDumpFile.exists()) {
      Exception exception = new IllegalArgumentException("File does not exist: " + heapDumpFile);      return failure(exception, since(analysisStartNanoTime));
    }
    ISnapshot snapshot = null;    try {
      snapshot = openSnapshot(heapDumpFile);//生成内存快照信息
      IObject leakingRef = findLeakingReference(referenceKey, snapshot);//查看内存的引用
      // False alarm, weak reference was cleared in between key check and heap dump.
      if (leakingRef == null) {        return noLeak(since(analysisStartNanoTime));
      }
      String className = leakingRef.getClazz().getName();
      AnalysisResult result =
          findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, true);      if (!result.leakFound) {
        result = findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, false);//寻找内存泄漏的路径
      }      return result;
    } catch (SnapshotException e) {      return failure(e, since(analysisStartNanoTime));
    } finally {
      cleanup(heapDumpFile, snapshot);
    }

总结checkForLeak方法
1.把.hprof转为 Snapshot

  snapshot = openSnapshot(heapDumpFile);

2.找出泄漏的对象/泄漏对象的最短路径

IObject leakingRef = findLeakingReference(referenceKey, snapshot);
AnalysisResult result =
findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, true);

findLeakingReference作用

      ①在snapshot快照中找到第一个弱引用即为内存发生泄漏的引用
      ②遍历这个对象的所有实例信息
      ③如果发现存在key值与之前定义封装好的key值相同,那么返回这个定位到的泄漏对象

findLeakTrace是通过获取内存泄漏的引用来获取泄漏路径的最短路径

了解LeakCanary的原理
  1. Activity Destroy()之后将它放在一个WeakReference中

  2. 将WeakReference关联到一个ReferenceQueue

  3. 查看ReferenceQueue是否存有Activity的引用

  4. 如果该Activity泄露了,Dump出heap信息,然后去分析泄漏路径

原文链接:http://www.apkbus.com/blog-344464-77310.html

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消