Leakcanary内存框架源码解析

1.LeakCanary一些准备知识

1.1LeakCanart简单介绍

  • 由Square开源的一款轻量第三方内存泄漏检测工具
  • 原理:watch一个即将销毁的对象

1.2内存

  • 栈:基本对象的应用
  • 堆:用来存放new的对象
  • 方法区:也称为静态区

1.3内存泄漏会导致什么问题

  • OOM

1.4android常见内存泄漏
1.4.1.单例造成的内存泄漏

public class SingletonActivityContext {
    private static SingletonActivityContext instance;
    private Context context;

    private SingletonActivityContext(Context context) {
      //原因SingletonActivityContext会持有你传入的Activity的实例对象,并会一直伴随着整个生命周期
        this.context = context;
    }

    public static SingletonActivityContext getInstance(Context context) {
        if (instance == null) {
            instance = new SingletonActivityContext(context);
        }
        return instance;
    }
}

解决办法:

ublic class SingletonAppliationContext {
    private static SingletonAppliationContext instance;
    private Context context;
    private SingletonAppliationContext(Context context) {
        this.context = context.getApplicationContext();// 使用Application 的context
    }
    public static SingletonAppliationContext getInstance(Context context) {
        if (instance == null) {
            instance = new SingletonAppliationContext(context);
        }
        return instance;
    }
}

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

public class StaticLeakActivity extends Activity {
    private static noneStaticClass mResource = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (mResource == null) {
            mResource = new noneStaticClass();
        }

    }
  //noneStaticClass 默认会持有StaticLeakActivity的实例对象,这样就会导致mResource一直持有StaticLeakActivity对象,此时它无法被回收
    private class noneStaticClass {

    }
}

1.4.3Handler导致的内存泄漏

public class HandlerLeakActivity extends Activity {
    private final Handler mLeakyHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//原因:消息被推送到消息队列中,finish会销毁当前activity,但是因为延迟发送的message还处于主线程中,这时候会持有activity的handler的使用,这时候activity就不会被销毁,因为message持有handler引用,而handler持有activity的引用
        mLeakyHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
            }
        }, 1000 * 60 * 10);

        finish();
    }
    /*
    * 解决办法:
    * 1.将 Handler 声明为静态的
    * 2.通过弱引用的方式引入 Activity
    *
    * /
}

1.4.4.线程造成的内存泄漏

public class ThreadLeakActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        testThreadLeak();
    }

    private void testThreadLeak() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(10000);
                return null;
            }
        }.execute();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(10000);
            }
        }).start();
    }
 }

解决办法

 static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        private WeakReference<Context> weakReference;

        public MyAsyncTask(Context context) {
            weakReference = new WeakReference<>(context);
        }

        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(10000);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            ThreadLeakActivity activity = (ThreadLeakActivity) weakReference.get();
            if (activity != null) {
                //...
            }
        }
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            SystemClock.sleep(10000);
        }
    }

1.4.5.Webview造成的内存泄漏

public class WebviewLeakActivity extends AppCompatActivity {
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //mWebView = (WebView) findViewById(R.id.wv_show);
        mWebView.loadUrl("http://www.baidu.com");
    }

    //解决办法
    @Override
    protected void onDestroy() {
        destroyWebView();
        android.os.Process.killProcess(android.os.Process.myPid());
        super.onDestroy();
    }

    private void destroyWebView() {
        if (mWebView != null) {
            mWebView.pauseTimers();
            mWebView.removeAllViews();
            mWebView.destroy();
            mWebView = null;
        }
    }

}

Leakcanary简单使用

1.原理:

  • Activity Destory之后将它放在一个WeakRefrenece
  • 这个WeakReference关联到ReferenceQueue
  • 查看ReferenceQueue是否存在Actiivty的引用
  • 如果该Activity泄露了,Dump出Heap信息,然后再去分析泄漏路径

2.4种应用

  • 强应用
  • 软应用:内存不足时会被回收
  • 弱应用:直接去回收
  • 虚应用:和没有应用是一样的

软应用和弱应用相同点;对象被垃圾回收,java虚拟机就会把这个应用加入到与之关联的引用队列中

3.github官网:https://github.com/square/leakcanary
4.gradle依赖:

//官方的
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
//因为我这里是android studio 2.3.3的版本
    compile 'com.squareup.leakcanary:leakcanary-android:1.5.4'

5.使用很简单: LeakCanary.install(this);

Leakcanary源码分析

1.install源码分析

  public static RefWatcher install(Application application) {
    return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
        .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
        //分析buildAndInstall
        .buildAndInstall();
  }

buildAndInstall源码分析

  public RefWatcher buildAndInstall() {
  //返回refWatcher
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
      //弹出告诉你那里泄漏,表示开启activity
      LeakCanary.enableDisplayLeakActivity(context);
      //继续看这个
      ActivityRefWatcher.install((Application) context, refWatcher);
    }
    return refWatcher;
  }

ActivityRefWatcher.install源码分析

  public static void install(Application application, RefWatcher refWatcher) {
    new ActivityRefWatcher(application, refWatcher).watchActivities();
  }
  public void watchActivities() {
    // 反注册我们以前的activitycallback
    stopWatchingActivities();
    //重新注册  看lifecycleCallbacks源码
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
  }
  public void stopWatchingActivities() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
  }

lifecycleCallbacks源码很长只要关注一行就可以了

 @Override public void onActivityDestroyed(Activity activity) {
       //和Application的onDestory的生命周期关联
          ActivityRefWatcher.this.onActivityDestroyed(activity);
}

  void onActivityDestroyed(Activity activity) {
  // 首先看下refWatcher有哪些成员变量,然后看watch的源码
    refWatcher.watch(activity);
  }
//refWatcher成员变量
  //用于内存检测
  private final WatchExecutor watchExecutor;
  //查询是否正在调试中
  private final DebuggerControl debuggerControl;
  //用于判断泄漏之前,给gc最后一次机会
  private final GcTrigger gcTrigger;
  //内存泄漏堆文件
  private final HeapDumper heapDumper;
  //key
  private final Set<String> retainedKeys;
  //判断弱应用所持有的对象是否被已经被gc垃圾回收
  private final ReferenceQueue<Object> queue;
  private final HeapDump.Listener heapdumpListener;
  //排除一些系统bug
  private final ExcludedRefs excludedRefs;
  public void watch(Object watchedReference) {
    watch(watchedReference, "");
  }
public void watch(Object watchedReference, String referenceName) {
    if (this == DISABLED) {
      return;
    }
    checkNotNull(watchedReference, "watchedReference");
    checkNotNull(referenceName, "referenceName");
    final long watchStartNanoTime = System.nanoTime();
    //添加的唯一的key
    String key = UUID.randomUUID().toString();
    retainedKeys.add(key);
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);
     //看这个源码
    ensureGoneAsync(watchStartNanoTime, reference);
  }

ensureGoneAsync源码分析

  private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
  //线程
    watchExecutor.execute(new Retryable() {
      @Override public Retryable.Result run() {
        return ensureGone(reference, watchStartNanoTime);
      }
    });
  }
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    //持续时间
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
     //移除已达到队列中的弱应用
    removeWeaklyReachableReferences();
    //如果是处于调试中则不进行分析
    if (debuggerControl.isDebuggerAttached()) {
       return RETRY;
    }
     if (gone(reference)) {
      return DONE;
    }
    //手动执行gc
    gcTrigger.runGc();
     //移除已达到队列中的弱应用
    removeWeaklyReachableReferences();
    if (!gone(reference)) {
      long startDumpHeap = System.nanoTime();
      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);

      File heapDumpFile = heapDumper.dumpHeap();
      if (heapDumpFile == RETRY_LATER) {
            return RETRY;
      }
      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
      //最后在线程中取开始分析我们的泄漏
      heapdumpListener.analyze(
 new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
              gcDurationMs, heapDumpDurationMs));
    }
    return DONE;
  }

analyze分析我们的泄漏

 void analyze(HeapDump heapDump);

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

HeapAnalyzerService.runAnalysis源码分析,因为这个方法是继承于IntentService方法,所以会回调onHandlerIntent方法

  public static void runAnalysis(Context context, HeapDump heapDump,
      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
    Intent intent = new Intent(context, HeapAnalyzerService.class);
    intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
    intent.putExtra(HEAPDUMP_EXTRA, heapDump);
    context.startService(intent);
  }
@Override protected void onHandleIntent(Intent intent) {
    if (intent == null) {
      CanaryLog.d("HeapAnalyzerService received a null intent, ignoring.");
      return;
    }
    //获得传来的值
    String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA);
    HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);
    //排除一些系统bug
    HeapAnalyzer heapAnalyzer = new HeapAnalyzer(heapDump.excludedRefs);
   //这个很重要
    AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey);
    //回调
    AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
  }

checkForLeak源码分析

 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));
    }

    try {
    //heapDumpFile封装成对象
      HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
      //解释器解析上面的buffer
      HprofParser parser = new HprofParser(buffer);
      //具体的解析工作
      Snapshot snapshot = parser.parse();
      //对我们所检查的结果去重
      deduplicateGcRoots(snapshot);
     //获得解析的结果
      Instance leakingRef = findLeakingReference(referenceKey, snapshot);
      if (leakingRef == null) {//表示对象不存在,表示已经清楚
        return noLeak(since(analysisStartNanoTime));
      }
      //找出泄漏的对象/找出泄漏对象的最短路径
      return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
    } catch (Throwable e) {
      return failure(e, since(analysisStartNanoTime));
    }
  }

1.把.hprof转化为Snapshot
2.优化gcroots
3.找出泄漏的对象/找出泄漏对象的最短路径

findLeakingReference源码分析

 private Instance findLeakingReference(String key, Snapshot snapshot) {
 //根据弱应用查找类的对象
    ClassObj refClass = snapshot.findClass(KeyedWeakReference.class.getName());
    List<String> keysFound = new ArrayList<>();
    //遍历这个对象的所有实例
    for (Instance instance : refClass.getInstancesList()) {
      List<ClassInstance.FieldValue> values = classInstanceValues(instance);
      String keyCandidate = asString(fieldValue(values, "key"));
      //如果key的值和最开始定义封装的key值相同,那么返回这个泄漏对象
      if (keyCandidate.equals(key)) {
        return fieldValue(values, "referent");
      }
      keysFound.add(keyCandidate);
    }

findLeakTrace源码分析

private AnalysisResult findLeakTrace(long analysisStartNanoTime, Snapshot snapshot,
      Instance leakingRef) {
       ShortestPathFinder pathFinder = new ShortestPathFinder(excludedRefs);
    ShortestPathFinder.Result result = pathFinder.findPath(snapshot, leakingRef);
     if (result.leakingNode == null) {
      return noLeak(since(analysisStartNanoTime));
    }
      //屏幕显示的就是这个
    LeakTrace leakTrace = buildLeakTrace(result.leakingNode);

    String className = leakingRef.getClassObj().getClassName();

    snapshot.computeDominators();

    Instance leakingInstance = result.leakingNode.instance;
    //计算内存泄漏的空间大小的
    long retainedSize = leakingInstance.getTotalRetainedSize();

    // TODO: check O sources and see what happened to android.graphics.Bitmap.mBuffer
    if (SDK_INT <= N_MR1) {
      retainedSize += computeIgnoredBitmapRetainedSize(snapshot, leakingInstance);
    }

    return leakDetected(result.excludingKnownLeaks, className, leakTrace, retainedSize,
        since(analysisStartNanoTime));
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值