首先从LeakCanary的使用开始讲,接着会到底层分析源码逻辑
kotlin新版本如何使用
dependencies {
// debugImplementation because LeakCanary should only run in debug builds.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}
只需要这样一步就搞定了.
默认监测哪些泄漏
官方网站的说明,无侵入式依赖,会自动给注入如下几个模块的内存泄漏监听
LeakCanary automatically detects leaks of the following objects:
destroyed Activity instances
destroyed Fragment instances
destroyed fragment View instances
cleared ViewModel instances
整体工作流程
它会经过下面4个步骤来完成所有的工作.
- Detecting retained objects. 监测保留未被回收的对象
- Dumping the heap. 转储堆区
- Analyzing the heap. 分析堆区
- Categorizing leaks. 堆泄漏进行分来
监测未被回收的对象
在前台可见的时候,是监听到有5个未回收的对象就会开始dump
在后台不可见的时候,是监听到有1个未被回收的对象就会开始dump.
2秒钟监测一次,dump的周期是5秒钟一次.
转储堆
当达到上面的阈值情况下,就会触发dump,
生成.hprof文件
分析堆区
现在是通过Shark来分析
泄漏分类
################################
步入正题,死磕源码.
编译后的文件里会有自动注入一些provider和activity.
1: ProcessLifecycleOwnerInitializer
androidx.lifecycle.ProcessLifecycleOwnerInitializer
这是安卓系统自带的一个ContentProvider
在onCreate方法里主要做了2个操作
LifecycleDispatcher.init(getContext());
ProcessLifecycleOwner.init(getContext());
1.1: LifecycleDispatcher
//底层会在application中把这个callback纳入application的维护范畴内
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
在注意看DispatcherActivityCallback中其实就做了一个事情
@VisibleForTesting
static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//核心就是这句了.
ReportFragment.injectIfNeededIn(activity);
}
..........省略.......................
}
上面的回调Callback 是Application中的一个接口,同时Application中维护了一个ArrayList
@UnsupportedAppUsage
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
1.2: ProcessLifecycleOwner
static void init(Context context) {
sInstance.attach(context);
}
void attach(Context context) {
mHandler = new Handler();
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
Application app = (Application) context.getApplicationContext();
//核心还是下面这行代码了 注册activity的生命周期回调
app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityPreCreated(@NonNull Activity activity,
@Nullable Bundle savedInstanceState) {
activity.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
.......省略.......
onActivityPostStarted
.......省略.......
onActivityPostResumed
.......省略.......
});
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < 29) {
ReportFragment.get(activity).setProcessListener(mInitializationListener);
}
}
.......省略.......
});
}
**总结: 上面的2个生命周期注册回调 ,最终都是在Application类中处理的.
public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.add(callback);
}
}
public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.remove(callback);
}
}
2: LeakCanaryFileProvider
leakcanary.internal.LeakCanaryFileProvider
这个类我也没看懂具体看嘛的, 大概意思就是操作file类时使用到.
3: MainProcessAppWatcherInstaller
leakcanary.internal.MainProcessAppWatcherInstaller
这个类也是集成了ContentProvider, 替代了以前老版本LeackCanary手动install, 在这个类的onCreate方法中会自动执行如下操作[神来之笔]
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
3.1: 核心代码
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
//校验当前是否在主线程 Looper.getMainLooper().thread === Thread.currentThread()
checkMainThread()
if (isInstalled) {
throw IllegalStateException(
"AppWatcher already installed, see exception cause for prior install call", installCause
)
}
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
installCause = RuntimeException("manualInstall() first called here")
this.retainedDelayMillis = retainedDelayMillis
if (application.isDebuggableBuild) {
//debug模式 打开日志开关
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
LeakCanaryDelegate.loadLeakCanary(application)
watchersToInstall.forEach {
it.install()
}
}
3.2: 反射加载InternalLeakCanary
@Suppress("UNCHECKED_CAST")
val loadLeakCanary by lazy {
try {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.ge