IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android性能优化之Leak Canary -> 正文阅读

[移动开发]Android性能优化之Leak Canary

Android 内存泄漏检测 LeakCanary 介绍及使用

官网点击这里 ,本文是对官网的大致翻译和加上自己的理解

一、使用🌚

使用 LeakCanary ,需要向 app 模块中的 build.gradle 文件中,添加:

dependencies {
  	debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
}

确认 LeakCanary 在启动的时候运行了可以在日志(Logcat)中查看是否有一下的输出:

D LeakCanary: LeakCanary is running and ready to detect leaks

目前,LeakCanary 回自动检测一下类型的内存泄漏:

- 销毁的 Activity 实例
- 销毁的 Fragment 实例
- 销毁的 fargment view 实例
- 清除过的 ViewModel 实例

二、介绍🌘

LeakCanary 是的工作原理和如何检测和修复内存泄漏 Bug。

什么是内存泄漏?

在 Java 运行时,内存泄漏就是指编程错误导致应用引用了一个不再需要的 Object,结果那个对象所占用的内存不能被回收,最终导致 OutOfMemoryError (OOM),程序崩溃

一般导致内存泄漏的原因

大部分导致内存泄漏的错误与对象的生命周期有关。 举几个栗子:

  • 添加一个 Fragment 实例备用,但是却没有在 Fragment.onDestoryView() 中清除视图字段(view fields)
  • 一个 Context 字段指向一个 Activity 实例,在应用配置发生变化的时候(例如屏幕旋转)引用的 Activity 实例会重建
  • 向一个有生命周期的对象注册(register)了 listener、broadcast recevier 或 RxJava subscription,结果在对象生命周期结束的时候忘记注销(unregister)

三、LeakCanary 工作原理🌗

工作分为4步:

  1. 检测遗留的对象
  2. 转存堆内存
  3. 分析堆
  4. 检测出内存泄漏

1、检测遗留的对象

LeakCanary 使用钩子(hooks)织入 android 的生命周期,自动检测活动和碎片什么时候销毁、什么时候被回收。这些销毁的对象会被以软引用(weak references)的方式传到一个 Objectwatcher 对象中,通过下面的方式可以看到不在需要的对象,例如下面的不适用的视图对象:

AppWatcher.objectWatcher.watch(myDetachedView, "View was detached")

如果 Objectwatcher 的弱引用在5秒并且运行了垃圾回收后没有被清除,则认为这个对象被保留并且有可能导致内存泄漏。并且会打印类似下面的日志:

D LeakCanary: Watching instance of com.example.leakcanary.MainActivity
  (Activity received Activity#onDestroy() callback) 

... 5 seconds later ...

D LeakCanary: Scheduling check for retained objects because found new object
  retained

LeakCanary 等到保留的对象达到一个阈值后进行堆内存的转存,并且会用通知提醒目前的个数,点击通知会立即进行堆内存的转存。关于阈值的设置,应用在前台的时候默认阈值是5,在后台(不可见)的时候阈值为1。

2、堆内存转存

按上文所说,遗留的对象到阈值后,LeakCanary 就会把Java的堆内存转成一个后缀为 .hprof 的文件存储到文件系统中,文件的存储需要获得 android.permission.WRITE_EXTERNAL_STORAGE 权限,存储到叫 leakcanary-com.example 的文件夹中,其中 com.example 是一你敢用的包名。在存的过程中应用会暂停运行一会,同时 LeakCanary 会给出提示。

3、分析堆内存

存储的 .hprof 文件会通过一个库在内存中定位到仍保留的对象,(这个不是我们要关心的),我们要关心的是对每个遗留对象,LeakCanary 都会找到一个阻止对象被回收的引用路径叫 leak trace。分析完毕 LeakCanary 会将结果打印在 Logcat 中,如下。LeakCanary 会对每个 leak trace 生成一个签名,然后对leak根据签名分组,每组 leaks 产生的都是因为相同的错误。

====================================
HEAP ANALYSIS RESULT
====================================
2 APPLICATION LEAKS

Displaying only 1 leak trace out of 2 with the same signature
Signature: ce9dee3a1feb859fd3b3a9ff51e3ddfd8efbc6
┬───
│ GC Root: Local variable in native code
│
...

LeakCanary 会生在应用列表中生成一个启动图标。每个相关的引用都会被在下面用一个红线标识,当使用文本分享的时候就类似于下面这样,用~~~~标识:

...
│  
├─ com.example.leakcanary.LeakingSingleton class
│    Leaking: NO (a class is never leaking)
│    ↓ static LeakingSingleton.leakedViews
│                              ~~~~~~~~~~~
├─ java.util.ArrayList instance
│    Leaking: UNKNOWN
│    ↓ ArrayList.elementData
│                ~~~~~~~~~~~
├─ java.lang.Object[] array
│    Leaking: UNKNOWN
│    ↓ Object[].[0]
│               ~~~
├─ android.widget.TextView instance
│    Leaking: YES (View.mContext references a destroyed activity)
...

4、检测内存泄漏

LeakCanary 将泄漏分为应用泄漏( Application Leaks)和三方库泄漏(Library Leaks)。第三方库导致的内存泄漏能被标识出来,影响到自己的应用,但是这个问题不是我们能控制,当然也可以使用反射或者向作者报告这种错误。

四、解决内存泄漏问题🌖

这个过程也分四步:

1. 找到 leak trace
2. 缩小怀疑的引用的范围
3. 找到导致泄漏的原因
4. 在代码层面修复 bug

1、找到泄漏的引用路径

介绍GC root 概念,GC roots 是标识那些总是可达的对象,就表示他们是不能被回收的,主要包括以下四类:

1、本地变量,属于一个线程
2、正在运行中的Java 线程的实例
3、系统类,从不被卸载
4、本地方法引用,是被本地方法的代码控制

2、缩小可疑范围

在一个泄漏路径中,开始的时候所有的引用都是被怀疑的对象, LeakCanary 能自动缩小可疑范围。具体过程就是,先标记所有的引用对象,然后在路径上从上到下,一个一个检测,对象是能被回收,如果是导致泄漏的,则会在对象前面加上一句LEAKING:YES 原因,如下:

┬───
│ GC Root: System class
│
├─ android.provider.FontsContract class
│    ↓ static FontsContract.sContext
├─ com.example.leakcanary.ExampleApplication instance
│    Leaking: NO (Application is a singleton)
│    ↓ ExampleApplication.leakedViews
│                         ~~~~~~~~~~~
├─ java.util.ArrayList instance
│    ↓ ArrayList.elementData
│                ~~~~~~~~~~~
├─ java.lang.Object[] array
│    ↓ Object[].[0]
│               ~~~
├─ android.widget.TextView instance
│    Leaking: YES (View.mContext references a destroyed activity)
│    ↓ TextView.mContext
╰→ com.example.leakcanary.MainActivity instance

3、根据缩小的范围找到导致泄漏的引用

4、找到以后修复错误🌞

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:51:16  更:2021-07-30 12:51:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 2:05:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码