博客
关于我
LeakCanary使用,案例静态Toast引起的内存泄漏
阅读量:792 次
发布时间:2023-01-30

本文共 3830 字,大约阅读时间需要 12 分钟。

LeakCanary: Android内存泄露检测工具详解

LeakCanary是一个强大的Android内存泄露检测工具,它能够帮助开发者发现和修复内存泄露问题。本文将指导您如何使用LeakCanary以及如何通过它检测并解决内存泄露问题。

首先,了解LeakCanary的基本工作原理。LeakCanary基于ObjectWatcher library,它通过hook Android的生命周期方法,监视Activity和Fragment的销毁过程。 在对象被销毁时,ObjectWatcher会创建弱引用(WeakReference),跟踪这些对象是否被垃圾回收。如果在GC处理后这些对象仍然存在,LeakCanary会记录这些泄漏对象,并通过Logcat输出日志。

在项目中加入LeakCanary非常简单。只需在项目的Gradle文件中添加以下依赖:

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'请注意,这个依赖仅在debug模式下生效,因此在生产环境中不会影响应用性能。

在项目运行后,随便在应用中点击某个地方,控制台会显示LeakCanary的工作日志。例如,以下日志表明应用正在检测内存泄露:

    D/LeakCanary: Check for retained object found no objects remaining    D/LeakCanary: Scheduling check for retained objects in 5000ms because app became invisible    D/LeakCanary: Check for retained object found no objects remaining    D/LeakCanary: Rescheduling check for retained objects in 2000ms because found only 3 retained objects ( < 5 while app visible )
这些日志表明LeakCanary正在不断监测应用中的保留对象数量。

如果在应用/activity切换后,LeakCanary会提示你有内部存储权限未授予,从而跳过堆转储。点击通知后,LeakCanary会生成.hprof文件并通过Logcat显示转储结果。 Fraser static板书式的 Prison Distribute(代码中隐藏的图片)。

在转储结果中,LeakCanary会提供详细的泄漏路径分析。以下是转储结果的示例:

    1 APPLICATION LEAKS    References underlined with "~~~" are likely causes.    Learn more at https://squ.re/leaks.    111729 bytes retained by leaking objects    Signature: e030ebe81011d69c7a43074e799951b65ea73a    ┬───    │ GC Root: Local variable in native code    │    ├─ android.os.HandlerThread instance    │    Leaking: NO (PathClassLoader↓ is not leaking)    │    Thread name: 'LeakCanary-Heap-Dump'    │    ↓ HandlerThread.contextClassLoader    ├─ dalvik.system.PathClassLoader instance    │    Leaking: NO (ToastUtil↓ is not leaking and A ClassLoader is never leaking)    │    ↓ PathClassLoader.runtimeInternalObjects    ├─ java.lang.Object[] array    │    Leaking: NO (ToastUtil↓ is not leaking)    │    ↓ Object[].[871]    ├─ com.example.leakcaneraytestapplication.ToastUtil class    │    Leaking: NO (a class is never leaking)    │    ↓ static ToastUtil.mToast    ├─ android.widget.Toast instance    │    Leaking: YES (This toast is done showing (Toast.mTN.mWM != null && Toast.mTN.mView == null))    │    ↓ Toast.mContext    ╰→ com.example.leakcaneraytestapplication.LeakActivity instance
通过分析泄漏路径,可以发现内存泄露的具体原因。例如,Toast对象未正确释放,导致内存无法回收。

在自定义ToastUtil类中,确保不再创建静态Toast对象。可以通过将Toast对象置为null来修复泄漏。以下是ToastUtil类的示例代码: public class ToastUtil { private static Toast mToast; public static void showToast(Context context, int resId) { String text = context.getString(resId); showToast(context, text); } public static void showToast(Context context, String text) { showToast(context, text, Gravity.BOTTOM); } public static void showToastCenter(Context context, String text) { showToast(context, text, Gravity.CENTER); } public static void showToast(Context context, String text, int gravity) { cancelToast(); if (context != null) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.toast_layout, null); ((TextView) layout.findViewById(R.id.tv_toast_text)) .setText(text); mToast = new Toast(context); mToast.setView(layout); mToast.setGravity(gravity, 0, 20); mToast.setDuration(Toast.LENGTH_LONG); mToast.show(); } } public static void cancelToast() { if (mToast != null) { mToast.cancel(); } } }通过将mToast置为null,可以避免静态对象的泄漏。

总之,内存泄露的根源是长生命周期的对象持有了短生命周期对象的引用。LeakCanary通过监测对象的销毁和垃圾回收状态,帮助开发者定位内存泄露来源,并提供解决方案。希望本文能帮助您更好地理解LeakCanary的使用方法。

转载地址:http://btgyk.baihongyu.com/

你可能感兴趣的文章
Lamp(Fpm-Php)基本配置
查看>>
laradock 安装使用 kafka
查看>>
laravel 5.3 给容器传参
查看>>
laravel 5.5 -- Eloquent 模型关联
查看>>
laravel mix
查看>>
Laravel Passport
查看>>
laravel 之 Eloquent 模型修改器和序列化
查看>>
Laravel 使用 - artisan schedule使用
查看>>
Laravel 使用rdkafka
查看>>
Laravel 多环境配置
查看>>
laravel 学习之第一章
查看>>
laravel 学习之第二章
查看>>
Laravel 安装上传代码不完整的解决方法
查看>>
laravel 安装添加多站点
查看>>
Laravel 模型
查看>>
Laravel 深入理解路由和URL生成
查看>>
laravel 生命周期与框架精髓
查看>>
laravel 表单验证
查看>>
laravel 调试sql
查看>>
laravel 路由缓存
查看>>