深度揭秘:Android LeakCanary 核心初始化模块使用原理大剖析
一、引言
在 Android 应用开发的广袤领域中,内存泄漏一直是困扰开发者的一大难题。内存泄漏会导致应用的内存占用不断增加,进而引发应用卡顿、崩溃等严重问题,极大地影响用户体验。为了有效检测和解决内存泄漏问题,Square 公司开源了一款强大的内存泄漏检测工具——LeakCanary。LeakCanary 能够在应用运行过程中自动检测内存泄漏,并及时提供详细的泄漏报告,帮助开发者快速定位和修复问题。
LeakCanary 的核心初始化模块是整个框架的基石,它负责完成 LeakCanary 的各项初始化工作,为后续的内存泄漏检测奠定基础。深入理解该模块的使用原理,对于开发者更好地运用 LeakCanary 进行内存泄漏检测至关重要。本文将从源码级别深入分析 Android LeakCanary 核心初始化模块的使用原理,带领读者一步步揭开其神秘面纱。
二、LeakCanary 概述
2.1 LeakCanary 的基本概念
LeakCanary 是一个开源的 Android 内存泄漏检测库,它采用了自动化的方式来检测应用中的内存泄漏问题。其核心原理是通过监控对象的生命周期,当一个对象应该被回收但却没有被回收时,LeakCanary 会触发堆转储(Heap Dump)操作,将应用的内存快照保存下来,然后对堆转储文件进行分析,找出导致对象无法被回收的引用链,从而确定内存泄漏的位置。
2.2 LeakCanary 的主要优势
- 自动化检测:LeakCanary 能够自动监控应用中的对象生命周期,无需开发者手动编写大量的检测代码,大大提高了内存泄漏检测的效率。
- 详细报告:当检测到内存泄漏时,LeakCanary 会生成详细的泄漏报告,包括泄漏对象的引用链、类名、堆栈信息等,帮助开发者快速定位和修复问题。
- 易于集成:LeakCanary 提供了简单易用的 API,开发者可以轻松地将其集成到自己的项目中。
2.3 LeakCanary 的应用场景
LeakCanary 适用于各种 Android 应用开发场景,特别是在以下情况下使用效果显著:
- 开发阶段:在应用开发过程中,使用 LeakCanary 可以及时发现和解决内存泄漏问题,避免问题积累到上线阶段。
- 测试阶段:在应用测试过程中,LeakCanary 可以作为一种辅助测试工具,帮助测试人员发现潜在的内存泄漏问题。
- 线上监控:对于一些对内存性能要求较高的应用,可以在上线后集成 LeakCanary 的轻量级版本,实时监控应用的内存泄漏情况。
三、核心初始化模块的基本概念
3.1 初始化的定义
初始化是指在程序启动或某个组件开始工作之前,对其进行必要的设置和准备工作的过程。在 LeakCanary 中,核心初始化模块负责完成一系列的初始化操作,包括配置参数的设置、组件的创建和注册等,以确保 LeakCanary 能够正常工作。
3.2 核心初始化模块的作用
核心初始化模块在 LeakCanary 中起着至关重要的作用,主要体现在以下几个方面:
- 配置参数设置:通过初始化模块,可以设置 LeakCanary 的各种配置参数,如检测阈值、报告生成方式等,以满足不同应用的需求。
- 组件创建和注册:初始化模块会创建 LeakCanary 的各个核心组件,如监控器、分析器等,并将它们注册到相应的系统中,以便在应用运行过程中能够正常工作。
- 环境检查和准备:在初始化过程中,会对应用的运行环境进行检查,确保 LeakCanary 能够在当前环境下正常工作。同时,还会进行一些必要的准备工作,如创建文件目录、加载资源等。
3.3 核心初始化模块的重要性
核心初始化模块是 LeakCanary 正常工作的基础。如果初始化过程出现问题,可能会导致 LeakCanary 无法正常检测内存泄漏,或者生成错误的检测报告。因此,深入理解核心初始化模块的使用原理,对于正确使用 LeakCanary 进行内存泄漏检测至关重要。
四、核心初始化模块的源码分析
4.1 初始化入口点
4.1.1 LeakCanary 类的静态方法
// LeakCanary 类,提供了 LeakCanary 的初始化和使用接口
public final class LeakCanary {
// 静态方法,用于安装 LeakCanary
public static RefWatcher install(Application application) {
// 创建一个默认的 LeakCanary 配置
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
// 静态方法,用于创建一个 RefWatcherBuilder 实例
public static RefWatcherBuilder refWatcher(Context context) {
// 返回一个新的 RefWatcherBuilder 实例,传入应用上下文
return new RefWatcherBuilder<>(context);
}
}
在上述代码中,LeakCanary 类提供了一个静态方法 install(),该方法是 LeakCanary 初始化的入口点。在 install() 方法中,首先调用 refWatcher() 方法创建一个 RefWatcherBuilder 实例,然后对该实例进行一系列的配置,最后调用 buildAndInstall() 方法完成 LeakCanary 的安装和初始化。
4.1.2 RefWatcherBuilder 类的作用
// RefWatcherBuilder 类,用于构建 RefWatcher 实例
public class RefWatcherBuilder<T extends RefWatcherBuilder<T>> {
// 应用上下文
private final Context context;
// 用于存储排除的引用
private ExcludedRefs excludedRefs;
// 用于存储监听泄漏的服务类
private Class<? extends AbstractAnalysisResultService> listenerServiceClass;
// 构造函数,初始化应用上下文
public RefWatcherBuilder(Context context) {
this.context = context.getApplicationContext();
}
// 设置排除的引用
public T excludedRefs(ExcludedRefs excludedRefs) {
this.excludedRefs = excludedRefs;
return (T) this;
}
// 设置监听泄漏的服务类
public T listenerServiceClass(Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
this.listenerServiceClass = listenerServiceClass;
return (T) this;
}
// 构建并安装 RefWatcher 实例
public RefWatcher buildAndInstall() {
if (isInAnalyzerProcess(context)) {
// 如果当前进程是分析进程,则不进行安装
return RefWatcher.DISABLED;
}
// 调用 enableDisplayLeakActivity() 方法启用显示泄漏信息的 Activity
enableDisplayLeakActivity(context);
// 创建一个 AndroidResourceProvider 实例,用于提供 Android 资源
AndroidResourceProvider resourceProvider = new AndroidResourceProvider(context);
// 创建一个 DebuggerControl 实例,用于控制调试器
DebuggerControl debuggerControl = new AndroidDebuggerControl();
// 创建一个 HeapDumper 实例,用于进行堆转储
HeapDumper heapDumper = new AndroidHeapDumper(context, resourceProvider);
// 创建一个 ResourceReleasingExecutor 实例,用于执行资源释放任务
ResourceReleasingExecutor watchExecutor = new AndroidWatchExecutor(Looper.getMainLooper());
// 创建一个 LeakCanaryInternals 实例,用于管理 LeakCanary 的内部状态
LeakCanaryInternals leakCanaryInternals = new LeakCanaryInternals(context);
if (listenerServiceClass != null) {
// 如果设置了监听泄漏的服务类,则将其添加到 LeakCanaryInternals 中
leakCanaryInternals.setListenerServiceClass(listenerServiceClass);
}
// 调用 watchActivities() 方法监听 Activity 的生命周期
leakCanaryInternals.watchActivities(context, watchExecutor);
// 调用 watchFragments() 方法监听 Fragment 的生命周期
leakCanaryInternals.watchFragments(context, watchExecutor);
// 创建一个 HeapDumpTrigger 实例,用于触发堆转储
HeapDumpTrigger heapDumpTrigger = new HeapDumpTrigger(context, watchExecutor, debuggerControl, heapDumper,
leakCanaryInternals.leakDirectoryProvider, excludedRefs);
// 创建一个 RefWatcher 实例
RefWatcher refWatcher = new RefWatcher(watchExecutor, debuggerControl, heapDumpTrigger, heapDumper,
excludedRefs);
// 将 RefWatcher 实例设置为全局的 RefWatcher
LeakCanaryInternals.setRefWatcher(context, refWatcher);
return refWatcher;
}
// 判断当前进程是否是分析进程
private static boolean isInAnalyzerProcess(Context context) {
// 获取当前进程的名称
String processName = LeakCanaryInternals.getProcessName(context);
// 获取分析进程的名称
String analyzerProcessName = context.getPackageName() + ":leakcanary-analyzer";
// 判断当前进程名称是否等于分析进程名称
return analyzerProcessName.equals(processName);
}
// 启用显示泄漏信息的 Activity
private static void enableDisplayLeakActivity(Context context) {
// 获取 PackageManager 实例
PackageManager packageManager = context.getPackageManager();
// 获取显示泄漏信息的 Activity 的组件名称
ComponentName componentName = new ComponentName(context, DisplayLeakActivity.class);
// 设置显示泄漏信息的 Activity 的启用状态
packageManager.setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
}
RefWatcherBuilder 类用于构建 RefWatcher 实例,它提供了一系列的配置方法,如 excludedRefs()、listenerServiceClass() 等,用于设置 RefWatcher 的各种参数。在 buildAndInstall() 方法中,首先判断当前进程是否是分析进程,如果是,则不进行安装;然后启用显示泄漏信息的 Activity;接着创建各种核心组件,如 AndroidResourceProvider、DebuggerControl、HeapDumper 等;最后创建 RefWatcher 实例并将其设置为全局的 RefWatcher。
4.2 配置参数设置
4.2.1 排除的引用配置
// ExcludedRefs 类,用于存储排除的引用
public final class ExcludedRefs {
// 用于存储排除的静态字段引用
private final Map<Class<?>, Set<String>> excludedStaticFields;
// 用于存储排除的实例字段引用
private final Map<Class<?>, Set<String>> excludedInstanceFields;
// 构造函数,初始化排除的静态字段引用和实例字段引用
private ExcludedRefs(Map<Class<?>, Set<String>> excludedStaticFields,
Map<Class<?>, Set<String>> excludedInstanceFields) {
this.excludedStaticFields = excludedStaticFields;
this.excludedInstanceFields = excludedInstanceFields;
}
// 静态内部类,用于构建 ExcludedRefs 实例
public static final class Builder {
// 用于存储排除的静态字段引用
private final Map<Class<?>, Set<String>> excludedStaticFields = new HashMap<>();
// 用于存储排除的实例字段引用
private final Map<Class<?>, Set<String>> excludedInstanceFields = new HashMap<>();
// 排除静态字段引用
public Builder instanceField(Class<?> clazz, String fieldName) {
// 获取该类对应的排除实例字段集合
Set<String> fields = excludedInstanceFields.computeIfAbsent(clazz, k -> new HashSet<>());
// 将字段名添加到集合中
fields.add(fieldName);
return this;
}
// 排除实例字段引用
public Builder staticField(Class<?> clazz, String fieldName) {
// 获取该类对应的排除静态字段集合
Set<String> fields = excludedStaticFields.computeIfAbsent(clazz, k -> new HashSet<>());
// 将字段名添加到集合中
fields.add(fieldName);
return this;
}
// 构建 ExcludedRefs 实例
public ExcludedRefs build() {
return new ExcludedRefs(excludedStaticFields, excludedInstanceFields);
}
}
// 获取排除的静态字段引用
public Map<Class<?>, Set<String>> getExcludedStaticFields() {
return excludedStaticFields;
}
// 获取排除的实例字段引用
public Map<Class<?>, Set<String>> getExcludedInstanceFields() {
return excludedInstanceFields;
}
}
在 RefWatcherBuilder 类的 excludedRefs() 方法中,可以设置排除的引用。ExcludedRefs 类用于存储排除的引用,它包含两个 Map,分别用于存储排除的静态字段引用和实例字段引用。ExcludedRefs.Builder 类提供了 instanceField() 和 staticField() 方法,用于添加排除的实例字段和静态字段。
4.2.2 监听泄漏的服务类配置
// 在 RefWatcherBuilder 类中
public T listenerServiceClass(Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
this.listenerServiceClass = listenerServiceClass;
return (T) this;
}
在 RefWatcherBuilder 类的 listenerServiceClass() 方法中,可以设置监听泄漏的服务类。该服务类用于接收内存泄漏分析结果,并进行相应的处理,如显示通知、保存报告等。
4.3 核心组件的创建和注册
4.3.1 AndroidResourceProvider 组件
// AndroidResourceProvider 类,用于提供 Android 资源
public class AndroidResourceProvider implements ResourceProvider {
// 应用上下文
private final Context context;
// 构造函数,初始化应用上下文
public AndroidResourceProvider(Context context) {
this.context = context.getApplicationContext();
}
@Override
public String getString(int resId) {
// 根据资源 ID 获取字符串资源
return context.getString(resId);
}
@Override
public String getString(int resId, Object... formatArgs) {
// 根据资源 ID 和格式化参数获取字符串资源
return context.getString(resId, formatArgs);
}
}
AndroidResourceProvider 类实现了 ResourceProvider 接口,用于提供 Android 资源。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 AndroidResourceProvider 实例,用于在后续的操作中获取字符串资源。
4.3.2 DebuggerControl 组件
// AndroidDebuggerControl 类,用于控制调试器
public class AndroidDebuggerControl implements DebuggerControl {
@Override
public boolean isDebuggerAttached() {
// 判断是否有调试器附加
return Debug.isDebuggerConnected();
}
}
AndroidDebuggerControl 类实现了 DebuggerControl 接口,用于控制调试器。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 AndroidDebuggerControl 实例,用于在堆转储时判断是否有调试器附加。
4.3.3 HeapDumper 组件
// AndroidHeapDumper 类,用于进行堆转储
public class AndroidHeapDumper implements HeapDumper {
// 应用上下文
private final Context context;
// 资源提供者
private final ResourceProvider resourceProvider;
// 堆转储文件的目录提供者
private final LeakDirectoryProvider leakDirectoryProvider;
// 构造函数,初始化应用上下文、资源提供者和堆转储文件的目录提供者
public AndroidHeapDumper(Context context, ResourceProvider resourceProvider) {
this.context = context.getApplicationContext();
this.resourceProvider = resourceProvider;
this.leakDirectoryProvider = new AndroidLeakDirectoryProvider(context);
}
@Override
public File dumpHeap() {
// 创建堆转储文件的名称
File heapDumpFile = leakDirectoryProvider.newHeapDumpFile();
if (heapDumpFile == null) {
// 如果无法创建堆转储文件,记录错误信息并返回 null
CanaryLog.d("Could not create heap dump file in " + leakDirectoryProvider);
return null;
}
try {
// 进行堆转储操作
Debug.dumpHprofData(heapDumpFile.getAbsolutePath());
return heapDumpFile;
} catch (IOException e) {
// 处理堆转储过程中出现的异常
deleteFile(heapDumpFile);
CanaryLog.d(e, "Could not dump heap to file %s", heapDumpFile);
return null;
}
}
// 删除文件
private void deleteFile(File file) {
if (!file.delete() && file.exists()) {
CanaryLog.d("Could not delete file %s", file);
}
}
}
AndroidHeapDumper 类实现了 HeapDumper 接口,用于进行堆转储。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 AndroidHeapDumper 实例,用于在检测到内存泄漏时进行堆转储操作。
4.3.4 AndroidWatchExecutor 组件
// AndroidWatchExecutor 类,用于在 Android 环境中执行任务
public class AndroidWatchExecutor implements Executor {
// 主线程的 Looper
private final Looper mainLooper;
// 构造函数,初始化主线程的 Looper
public AndroidWatchExecutor(Looper mainLooper) {
this.mainLooper = mainLooper;
}
@Override
public void execute(Runnable command) {
// 将任务发布到主线程的消息队列中执行
new Handler(mainLooper).post(command);
}
}
AndroidWatchExecutor 类实现了 Executor 接口,用于在 Android 环境中执行任务。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 AndroidWatchExecutor 实例,用于执行资源释放任务。
4.3.5 LeakCanaryInternals 组件
// LeakCanaryInternals 类,用于管理 LeakCanary 的内部状态
public class LeakCanaryInternals {
// 应用上下文
private final Context context;
// 监听泄漏的服务类
private Class<? extends AbstractAnalysisResultService> listenerServiceClass;
// 堆转储文件的目录提供者
private final LeakDirectoryProvider leakDirectoryProvider;
// 构造函数,初始化应用上下文和堆转储文件的目录提供者
public LeakCanaryInternals(Context context) {
this.context = context.getApplicationContext();
this.leakDirectoryProvider = new AndroidLeakDirectoryProvider(context);
}
// 设置监听泄漏的服务类
public void setListenerServiceClass(Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
this.listenerServiceClass = listenerServiceClass;
}
// 监听 Activity 的生命周期
public void watchActivities(Context context, Executor watchExecutor) {
// 获取 ActivityLifecycleCallbacks 实例
ActivityLifecycleCallbacks activityLifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override
public void onActivityDestroyed(Activity activity) {
// 在 Activity 销毁时,开始监控该 Activity 是否泄漏
LeakCanaryInternals.getRefWatcher(context).watch(activity);
}
};
// 获取 Application 实例
Application application = (Application) context.getApplicationContext();
// 注册 ActivityLifecycleCallbacks
application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
}
// 监听 Fragment 的生命周期
public void watchFragments(Context context, Executor watchExecutor) {
// 检查是否支持 Fragment
if (SDK_INT < HONEYCOMB) {
return;
}
// 获取 Application 实例
Application application = (Application) context.getApplicationContext();
// 检查是否支持 v4 包的 Fragment
if (isSupportFragmentAvailable()) {
// 注册 v4 包的 Fragment 生命周期回调
registerFragmentLifecycleCallbacks(application, new SupportFragmentLifecycleCallbacks(watchExecutor), true);
}
if (isAndroidXFragmentAvailable()) {
// 注册 AndroidX 包的 Fragment 生命周期回调
registerFragmentLifecycleCallbacks(application, new AndroidXFragmentLifecycleCallbacks(watchExecutor), true);
}
}
// 获取全局的 RefWatcher 实例
public static RefWatcher getRefWatcher(Context context) {
// 从 Application 的属性中获取 RefWatcher 实例
return ((Application) context.getApplicationContext()).getRefWatcher();
}
// 设置全局的 RefWatcher 实例
public static void setRefWatcher(Context context, RefWatcher refWatcher) {
// 将 RefWatcher 实例设置到 Application 的属性中
((Application) context.getApplicationContext()).setRefWatcher(refWatcher);
}
// 其他方法...
}
LeakCanaryInternals 类用于管理 LeakCanary 的内部状态。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 LeakCanaryInternals 实例,并调用其 watchActivities() 和 watchFragments() 方法,分别监听 Activity 和 Fragment 的生命周期,在 Activity 或 Fragment 销毁时,开始监控其是否泄漏。
4.3.6 HeapDumpTrigger 组件
// HeapDumpTrigger 类,用于触发堆转储
public class HeapDumpTrigger {
// 应用上下文
private final Context context;
// 执行任务的 Executor
private final Executor watchExecutor;
// 调试器控制组件
private final DebuggerControl debuggerControl;
// 堆转储组件
private final HeapDumper heapDumper;
// 堆转储文件的目录提供者
private final LeakDirectoryProvider leakDirectoryProvider;
// 排除的引用
private final ExcludedRefs excludedRefs;
// 构造函数,初始化各种组件和参数
public HeapDumpTrigger(Context context, Executor watchExecutor, DebuggerControl debuggerControl,
HeapDumper heapDumper, LeakDirectoryProvider leakDirectoryProvider,
ExcludedRefs excludedRefs) {
this.context = context;
this.watchExecutor = watchExecutor;
this.debuggerControl = debuggerControl;
this.heapDumper = heapDumper;
this.leakDirectoryProvider = leakDirectoryProvider;
this.excludedRefs = excludedRefs;
}
// 监控对象是否泄漏
public void watch(Object watchedReference, String referenceName) {
// 创建一个 KeyedWeakReference 实例,用于弱引用被监控的对象
final KeyedWeakReference reference = new KeyedWeakReference(watchedReference, referenceName,
queue, randomKey());
// 执行任务,检查对象是否泄漏
watchExecutor.execute(() -> checkForLeak(reference, referenceName));
}
// 检查对象是否泄漏
private void checkForLeak(KeyedWeakReference reference, String referenceName) {
// 判断是否有调试器附加
if (debuggerControl.isDebuggerAttached()) {
// 如果有调试器附加,不进行检查
return;
}
// 等待一段时间,让垃圾回收器有机会回收对象
waitForGc();
// 判断对象是否已经被回收
if (isGone(reference)) {
// 如果对象已经被回收,记录日志
CanaryLog.d("%s: GC'd", referenceName);
return;
}
// 触发堆转储操作
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == null) {
// 如果堆转储失败,记录错误信息
CanaryLog.d("Could not dump heap.");
return;
}
// 分析堆转储文件
analyzeHeap(reference, referenceName, heapDumpFile);
}
// 等待垃圾回收
private void waitForGc() {
// 进行一次垃圾回收
System.gc();
try {
// 等待一段时间,让垃圾回收器有机会执行
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError();
}
}
// 判断对象是否已经被回收
private boolean isGone(KeyedWeakReference reference) {
// 从弱引用队列中移除已经被回收的对象
removeWeaklyReachableReferences();
// 判断该弱引用是否还在队列中
return !queue.contains(reference);
}
// 移除弱引用队列中已经被回收的对象
private void removeWeaklyReachableReferences() {
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
// 从引用集合中移除该引用
retainedKeys.remove(ref.key);
}
}
// 分析堆转储文件
private void analyzeHeap(KeyedWeakReference reference, String referenceName, File heapDumpFile) {
// 创建一个 HeapDump 实例,包含堆转储文件和相关信息
HeapDump heapDump = new HeapDump(heapDumpFile, reference.key, referenceName, excludedRefs);
// 启动分析服务,分析堆转储文件
AbstractAnalysisResultService.sendResultToListener(context, listenerServiceClass, heapDump);
}
}
HeapDumpTrigger 类用于触发堆转储。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 HeapDumpTrigger 实例,用于在检测到对象可能泄漏时,触发堆转储操作,并对堆转储文件进行分析。
4.3.7 RefWatcher 组件
// RefWatcher 类,用于监控对象是否泄漏
public class RefWatcher {
// 执行任务的 Executor
private final Executor watchExecutor;
// 调试器控制组件
private final DebuggerControl debuggerControl;
// 堆转储触发组件
private final HeapDumpTrigger heapDumpTrigger;
// 堆转储组件
private final HeapDumper heapDumper;
// 排除的引用
private final ExcludedRefs excludedRefs;
// 构造函数,初始化各种组件和参数
public RefWatcher(Executor watchExecutor, DebuggerControl debuggerControl,
HeapDumpTrigger heapDumpTrigger, HeapDumper heapDumper,
ExcludedRefs excludedRefs) {
this.watchExecutor = watchExecutor;
this.debuggerControl = debuggerControl;
this.heapDumpTrigger = heapDumpTrigger;
this.heapDumper = heapDumper;
this.excludedRefs = excludedRefs;
}
// 监控对象是否泄漏
public void watch(Object watchedReference, String referenceName) {
// 调用堆转储触发组件的 watch 方法,监控对象是否泄漏
heapDumpTrigger.watch(watchedReference, referenceName);
}
}
RefWatcher 类用于监控对象是否泄漏。在 RefWatcherBuilder 类的 buildAndInstall() 方法中,创建了 RefWatcher 实例,并将其设置为全局的 RefWatcher。开发者可以通过调用 RefWatcher 的 watch() 方法,监控指定对象是否泄漏。
4.4 环境检查和准备
4.4.1 分析进程检查
// 在 RefWatcherBuilder 类中
private static boolean isInAnalyzerProcess(Context context) {
// 获取当前进程的名称
String processName = LeakCanaryInternals.getProcessName(context);
// 获取分析进程的名称
String analyzerProcessName = context.getPackageName() + ":leakcanary-analyzer";
// 判断当前进程名称是否等于分析进程名称
return analyzerProcessName.equals(processName);
}
在 RefWatcherBuilder 类的 buildAndInstall() 方法中,首先调用 isInAnalyzerProcess() 方法判断当前进程是否是分析进程。如果是分析进程,则不进行安装,避免重复初始化。
4.4.2 显示泄漏信息的 Activity 启用
// 在 RefWatcherBuilder 类中
private static void enableDisplayLeakActivity(Context context) {
// 获取 PackageManager 实例
PackageManager packageManager = context.getPackageManager();
// 获取显示泄漏信息的 Activity 的组件名称
ComponentName componentName = new ComponentName(context, DisplayLeakActivity.class);
// 设置显示泄漏信息的 Activity 的启用状态
packageManager.setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
在 RefWatcherBuilder 类的 buildAndInstall() 方法中,调用 enableDisplayLeakActivity() 方法启用显示泄漏信息的 Activity。这样,当检测到内存泄漏时,用户可以通过该 Activity 查看详细的泄漏信息。
4.4.3 堆转储文件目录创建
// AndroidLeakDirectoryProvider 类,用于提供堆转储文件的目录
public class AndroidLeakDirectoryProvider implements LeakDirectoryProvider {
// 应用上下文
private final Context context;
// 构造函数,初始化应用上下文
public AndroidLeakDirectoryProvider(Context context) {
this.context = context.getApplicationContext();
}
@Override
public File newHeapDumpFile() {
// 创建堆转储文件的目录
File heapDumpDir = new File(context.getExternalFilesDir(null), "leakcanary");
if (!heapDumpDir.exists()) {
// 如果目录不存在,则创建目录
if (!heapDumpDir.mkdirs()) {
// 如果创建目录失败,记录错误信息
CanaryLog.d("Could not create heap dump directory %s", heapDumpDir);
return null;
}
}
// 创建堆转储文件的名称
String fileName = "heapdump_" + new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US)
.format(new Date()) + ".hprof";
// 创建堆转储文件
return new File(heapDumpDir, fileName);
}
}
在 AndroidHeapDumper 类的构造函数中,创建了 AndroidLeakDirectoryProvider 实例,用于提供堆转储文件的目录。在 newHeapDumpFile() 方法中,会创建堆转储文件的目录,并生成堆转储文件的名称和路径。
五、核心初始化模块的使用示例
5.1 基本使用示例
import android.app.Application;
import leakcanary.LeakCanary;
// 自定义 Application 类
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 安装 LeakCanary
if (LeakCanary.isInAnalyzerProcess(this)) {
// 如果当前进程是分析进程,则不进行安装
return;
}
LeakCanary.install(this);
}
}
在上述示例中,创建了一个自定义的 Application 类 MyApplication,并在 onCreate() 方法中调用 LeakCanary.install(this) 方法安装 LeakCanary。这样,LeakCanary 会自动监控应用中 Activity 和 Fragment 的生命周期,当它们销毁时,会检查是否存在内存泄漏。
5.2 自定义配置示例
import android.app.Application;
import leakcanary.LeakCanary;
import leakcanary.RefWatcher;
import leakcanary.ExcludedRefs;
// 自定义 Application 类
public class MyApplication extends Application {
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
// 创建一个排除的引用配置
ExcludedRefs excludedRefs = ExcludedRefs.createAppDefaults()
.instanceField(MyClass.class, "myField")
.build();
// 自定义 LeakCanary 配置
refWatcher = LeakCanary.refWatcher(this)
.excludedRefs(excludedRefs)
.listenerServiceClass(MyAnalysisResultService.class)
.buildAndInstall();
}
// 获取全局的 RefWatcher 实例
public RefWatcher getRefWatcher() {
return refWatcher;
}
}
在上述示例中,通过 ExcludedRefs 类创建了一个排除的引用配置,排除了 MyClass 类的 myField 字段。然后,使用 LeakCanary.refWatcher() 方法创建一个 RefWatcherBuilder 实例,并对其进行自定义配置,最后调用 buildAndInstall() 方法完成 LeakCanary 的安装。
5.3 手动监控对象示例
import android.app.Activity;
import android.os.Bundle;
import leakcanary.LeakCanary;
import leakcanary.RefWatcher;
// 自定义 Activity 类
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
// 获取全局的 RefWatcher 实例
RefWatcher refWatcher = LeakCanary.install(this.getApplication());
// 手动监控一个对象
Object myObject = new Object();
refWatcher.watch(myObject, "MyObject");
}
}
在上述示例中,在 MyActivity 的 onCreate() 方法中,获取全局的 RefWatcher 实例,并手动监控一个对象 myObject。当 myObject 应该被回收但却没有被回收时,LeakCanary 会检测到内存泄漏并生成报告。
六、核心初始化模块的性能优化
6.1 减少不必要的初始化
在初始化过程中,应尽量减少不必要的对象创建和资源加载。例如,在判断当前进程是否是分析进程时,如果是分析进程,则不进行安装,避免重复初始化。另外,对于一些配置参数,如果不需要进行自定义设置,可以使用默认值,减少初始化的工作量。
6.2 优化组件创建和注册
在创建核心组件时,应尽量避免创建过多的临时对象,减少内存开销。例如,在创建 ExcludedRefs 实例时,可以复用已有的配置,避免重复创建。在注册组件时,应确保只注册必要的组件,避免注册过多的组件导致性能下降。
6.3 异步初始化
对于一些耗时的初始化操作,可以考虑采用异步初始化的方式,避免阻塞主线程。例如,在进行堆转储文件目录创建时,可以将其放在子线程中进行,提高应用的响应速度。