LeakCanary2源码分析

本文详细介绍了LeakCanary2在Android上的应用,包括其内存泄漏检测的原理,从添加依赖、简单实践到源码分析。重点讲解了ActivityDestroyWatcher和FragmentDestroyWatcher的安装过程,以及HeapAnalyzerService如何进行内存分析。通过对源码的深入理解,展示了LeakCanary2如何帮助开发者发现并解决内存泄漏问题。
摘要由CSDN通过智能技术生成


LeakCanary介绍

A memory leak detection library for Android.

LeakCanary是Android上用于检查内存泄漏的工具,LeakCanary大大减少因内存泄漏导致的内存溢出(OutOfMemoryError)奔溃,LeakCanary的易用和有效让它成为我最喜欢的开源框架之一,下面我们会先简单介绍其用法,然后深入了解LeakCanary检查内存泄漏的原理。

LeakCanary使用
加入依赖
dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
}

只需要添加相关依赖,便可集成,非常方便,如果从1.6版本升级,可以参考《Upgrading to LeakCanary 2》进行升级。

安装并启动APP,看到下面这个log,说明已经添加成功:

D/LeakCanary: Installing AppWatcher
简单实践
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d("MainActivity","Run");
            }
        }, 10000);
    }
}

这里我们写了个10s的延时任务,打开APP后迅速按返回键退出,这个时候LeakCanary有如下提示:

检查结果UI显示

LeakCanary的提示我们可以知道,MainActivity发生了内存泄漏,而泄漏的原因是MessageQueue持有了MainActivity,导致MainActivity无法正常退出,这里只是简单举例,大家可以加到自己项目中,相信会有不少收获。

LeakCanary源码分析

本文使用的是LeakCanary最新的2.2版本

从1.6.3开始,LeakCanary就使用Kotlin重写了一次,代码量(不包括空格和注释)从Java时期的6000增加到Kotlin版本的16000行,代码增加的原因是LeakCanary不在依赖HAHAperflib的重新打包),而是重新开发了自己的堆转储解析器:SharkShark的使用提升了速度并减少了内存使用。额外代码主要来自Shark, 自动化测试和权限相关的UI代码。

下面我们将开始分析全新的,Kotlin版本的LeakCnary:

1. 如何查看源码

因为我们使用的2.2版本,没有显式的框架入口,无法使用AndroidStudio的关联功能,所有我们要自己手动找代码,那么如何找到LeakCanary相关代码呢,我们需要到Lib里面找:

  1. 在Project Pannel中选择 “Project”

  2. 点击"External Libraries"

  3. 下拉找到LeakCanary的包,展开就可以看到相关代码

查看代码

我们可以看到LeakCanary的不少包,主要包括:

  • leakcanary-android

    集成入口模块,提供 LeakCanary 安装,公开 API 等能力

  • leakcanary-android-process

    和 leakcanary-android 一样,区别是会在单独的进程进行分析

  • leakcanary-android-core

    核心模块

  • leakcanary-object-watcher-android,leakcanary-object-watcher-android-androidx,leakcanary-watcher-android-support-fragments

    对象实例观察模块,在 ActivityFragment 等对象的生命周期中,注册对指定对象实例的观察,有 ActivityFragmentFragment ViewViewModel

  • shark-android

    提供特定于 Android 平台的分析能力。例如设备的信息,Android 版本,已知的内存泄露问题等

  • shark

    hprof 文件解析与分析的入口模块

  • shark-graph

    分析堆中对象的关系图模块

  • shark-hprof

    解析 hprof 文件模块

  • shark-log

    日志模块

2. 源码分析

LeakCanary 2.0不需要添加代码便可以跟随APP启动,原理在于利用了ContentProvider的特性,ContentProvider.onCreate方法会先于Application.onCreate执行。具体的实现只需要在AndroidManifeat.xml中配置一下定制的ContentProvider,在其onCreate方法中通过install进行初始化初始化,便可以省去LeakCanary 1.6版本中在Application中install的步骤:

//注册ContentProvider @leakcanary-object-watcher-android/src/main/AndroidManifest.xml
<application>
    <provider
        android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
        android:authorities="${applicationId}.leakcanary-installer"
        android:exported="false"/>
  </application>

首先在AndroidManifest.xml中注册contentProvider,然后对contentProvider进行定义:

//@AppWatcherInstaller.kt
internal class LeakCanaryProcess : AppWatcherInstaller() {
    override fun onCreate(): Boolean {
      super.onCreate()
      AppWatcher.config = AppWatcher.config.copy(enabled = false)
      return true
    }
  }

  override fun onCreate(): Boolean {
  	//获取application
    val application = context!!.applicationContext as Application
    //-->2.1 加载LeakCanary
    InternalAppWatcher.install(application)
    return true
  }
}

//2.1 加载LeakCanary @InternalAppWatcher.kt
fun install(application: Application) {
	...
	//检查当前线程是否有主线程
    checkMainThread()
    if (this::application.isInitialized) {
      //如果LeakCanary已经加载过,直接放回
      return
    }
    InternalAppWatcher.application = application

    val configProvider = { AppWatcher.config }
    //-->2.1监视Activity
    ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
    //-->2.2监视Fragment
    FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
    //-->2.3调用上层模块InternalLeakCanary.invoke
    onAppWatcherInstalled(application)
  }
2.1 ActivityDestroyWatcher.install
// @ActivityDestroyWatcher.kt
companion object {
   
  fun install(
    application: Application,
    objectWatcher: ObjectWatcher,
    configProvider: () -> Config
  ) {
   
    //-->2.1.1 创建Activity destroy监听回调
    val activityDestroyWatcher =
      ActivityDestroyWatcher(objectWatcher, configProvider)
    //-->2.1.2 同Application绑定
    application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
  }
}

//2.1.1 创建Activity destroy监听回调
  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
   
      override fun onActivityDestroyed(activity: Activity) {
   
        //Activity destroy触发存在对象检查
        if (configProvider().watchActivities) {
   
          // -->2.1.2 objectWatcher监视activity
          objectWatcher.watch
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值