所谓工欲善其事必先利其器,要想对内存泄露进行排查,那肯定少不了工具的运用。本章将会介绍三种工具来帮助你发现与解决这些内存泄露的问题。下一篇会总结遇到的内存泄露的问题。
分别是以下三个工具:
- LeakCanary
- Android Studio Profiler
- MAT
想必这个内存泄露监测库大家都不陌生了,
如何引入?一行代码解决debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
是的没错,最新版的LeakCanary只需要上面一行代码即可,相比以前还要在Application中注册省了一步。
注意:是 debugImplementation,不要设置成 implementation,debugImplementation是指在debug环境下生效。
如何使用?
当你把测试包安装到手机后,你就会发现手机上多了一个伴生App,他就是来记录你内存泄露的信息的。如下:
如果发生了内存泄露,App里会提示如下:
(好像泄露的有点多。。。)
点进去可以看到具体泄露的一些代码提醒,具体泄露的代码就需要自己去分析。因为我觉得他给的信息太少了。。还不方便,推荐使用LeakCanary来监测泄露,Android Studio Profiler来分析泄露问题。
三、Android Studio Profiler使用(推荐)部分数据信息来源安卓官网,建议看以下文章,官网有些信息没有及时同步。
Android Studio版本:Android Studio Bumblebee | 2021.1.1 Patch 2(当时最新的)
相比以前的Android Monitor 工具(简称摸你头工具),新版的Profiler简直不要太好。接下来我们看如何使用
如何使用?没错,直接点下面这个按钮Profiler按钮,就可以直接使用
根据下图 *** 作
接下来就是重中之中了
下面我们分别解释上面图显示信息的作用
分别解释以上功能:
- 垃圾桶按钮(应该是个垃圾桶吧):用于强制执行垃圾回收事件的按钮,也就是GC。(建议每次抓取是可以先点一下)
- Capture heap dump:抓取堆栈:(普通泄露问题分析就选这个就行了)
- Record native allocations:抓取原生内存(也就是C/C++)的分配
- Record Java/Kotlin allcations:抓取Java/Kotlin 内存分配
- Record:这个就简单了,点击一下就会抓取一段时间的内存分配信息。
分别解释以上文字信息:
- Others:您的应用使用的系统不确定如何分类的内存。
- Code:您的应用用于处理代码和资源(如 dex 字节码、经过优化或编译的 dex 代码、.so 库和字体)的内存。
- Stack:您的应用中的原生堆栈和 Java 堆栈使用的内存。这通常与您的应用运行多少线程有关。
- Graphics:图形缓冲区队列为向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。(请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)
-
Native:从 C 或 C++ 代码分配的对象的内存。
即使您的应用中不使用 C++,您也可能会看到此处使用了一些原生内存,因为即使您编写的代码采用 Java 或 Kotlin 语言,Android 框架仍使用原生内存代表您处理各种任务,如处理图像资源和其他图形。
-
Java:从 Java 或 Kotlin 代码分配的对象的内存。
-
Allocated:您的应用分配的 Java/Kotlin 对象数。此数字没有计入 C 或 C++ 中分配的对象。
这里我选择的是第一个 Capture heap dump选项,点击Record就可以看到如下图片:
- Leaks:当你有泄露时,这里会提示相应的类,可以点击跳转
您可以使用已分配对象列表上方的三个菜单选择需检查的堆以及如何组织数据。
从左侧的菜单中,选择需检查的堆:
- default heap:当系统未指定堆时。
- image heap:系统启动映像,包含启动期间预加载的类。此处的分配确保绝不会移动或消失。
- zygote heap:写时复制堆,其中的应用进程是从 Android 系统中派生的。
- app heap:您的应用在其中分配内存的主堆。
- JNI heap:显示 Java 原生接口 (JNI) 引用被分配和释放到什么位置的堆。
从中间的菜单中,选择如何安排分配:
- Arrange by class:根据类名称对所有分配进行分组。这是默认值。
- Arrange by package:根据软件包名称对所有分配进行分组。
- Arrange by callstack:将所有分配分组到其对应的调用堆栈。
从右侧的菜单中,选择如何安排分配:
- Show all classes:展示所有Class类(包括系统类),这是默认值。
- Show activity/fragment Leaks:展示泄露的activity/fragment。
- Show project class:展示项目的Class类。
在类列表中,您可以查看以下信息:
- Allocations:对象个数 , new一个对象就代表一个。,如果出现多个 , 就要考虑是否有内存泄漏了。
-
Native Size:此对象类型使用的原生内存总量(以字节为单位)。只有在使用 Android 7.0 及更高版本时,才会看到此列。
您会在此处看到采用 Java 分配的某些对象的内存,因为 Android 对某些框架类(如
Bitmap
)使用原生内存。 -
Shallow Size:此对象类型使用的 Java 内存总量(以字节为单位)。
-
Retained Size:为此类的所有实例而保留的内存总大小(以字节为单位)。
- Depth:从任意 GC 根到选定实例的最短跳数。
分析问题时主要关注:Allocations 和 Shallow Size。
好了,说了这么多这么水文的信息,接下来上一个项目实战的泄露问题分析实例。就一个,多的就没了。如图:
可以很明显的看到,CircleInfoActivity发生了内存泄露,至于泄露的原因其实就是被一个Static的变量持有着。
分析技巧:可以点击如图Show nearest GC root only 按钮,这时候就可以看到离他最近GC引用有两条,第一条很明显看不懂干嘛用的(老师说过:不会的可以先跳过),第二条就可以很明显看到他被mVideoViews所持有。如图:
找到问题,就很好解决了,在该释放的地方释放就好了。
(如果你还是找不到,那还是放开他吧Show nearest GC root only,然后慢慢找。。。,或者再试试下面MAT试试有没有新的发现)
四、MAT使用其实我在内存泄露问题分析上,基本上Profiler就可以发现问题了,至于没发现的,用了MAT也还是没发现。。。haha。接下来我们看如何使用:
MAT工具下载官方下载
百度云下载
JAVA环境配置由于最新版的MAT还需要JAVA 11,所以还需要配置JAVA 11的环境。
JAVA 11下载,需要登陆Oracle账号
百度云下载
JAVA 11环境配置:
很惊讶把,Java 8 和Java 11都有,记得把Java 11放到Java 8前面,这样Java环境才是11。可以CMD 》》Java -version 验证一下
hprof文件获取与格式转换1.Hprof文件获取
点击红色箭头按钮,便可以获取到Hprof文件。
2.Hprof格式转换
由于从Android studio中保存堆栈信息,由于Android studio的hprof文件格式与mat的格式不兼容,所以需要使用 安卓SDK 中的 hprof-conv.exe工具转换一下。
例如我的路径为:D:\20210426\androidSDK\platform-tools\hprof-conv.exe,其实就是你自己的安卓SDK下载路径,具体地址根据自己下载位置寻找。
最好就是把platform-tools文件夹的路径添加到系统环境变量中,方便使用。
2.1 hprof-conv 工具使用
hprof-conv -z srcFile dstFile
- -z 命令选项 : 表示排除非 APP 内存的堆 , 如 Zygote 内存等 ;
- srcFile 参数 : -z 后第一个参数是 源文件 , 即从 Android Studio 中保存的内存快照文件 , memory-20220421T102718.hprof
- dstFile 参数 : 后面的第二个参数是目标文件 , 即将转换后的结果保存到该文件中 ;
例如:hprof-conv -z memory-20220421T102718.hprof mat.hprof
memory-20220421T102718.hprof 也就是你从Android studio获取的Hprof文件了。
MAT使用1.打开MAT
2.导入Hprof文件,也就是你上面转化好的文件
3.选择Leak Suspects Report
4.点击Histogram
5.搜索有泄露问题的文件,例如上面提到的CircleInfoActivity
6.如下图 *** 作
排除虚、弱、软引用,因为这些基本不会发生泄露
7.点击后如下图,是不是发现和Android Studio Profiler的结果很像。
MAT其他功能补充饼图分析
可以看到,饼图里列出了两个会泄露的类。可以往下细致看看
看到这,一个是系统的HandleThread,一个是Class,这问题列了跟没列一样。
其实有时候还是有用的,那就是你泄露的类占用了很大的内存。
好了,到这里就结束了,下一篇会总结遇到的内存泄露。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)