android Profiler 实战-----内存泄露的分析与定位

一、Profiler是什么?

         Memory Profiler是Android Profiler中的一个组件,是Android Studio3.0用来替换之前Android Monitor的观察工具,主要用来观察内存,网络,cpu温度。它能够让你识别出内存泄漏和内存抖动,导致应用卡顿,anr和crash. 它可以给你展示一个内存使用的真实图表,让你知道当时内存使用情况,还能强制内存回收,和跟踪内存分配,可谓是性能分析的利器。

二、Profiler的使用

          1、连接手机,在AndroidStudio右上角的导航栏中有一个图标可以快速启动Profiler(红框中的图标),点击后会启动app。

                

          2、app启动后在AndroidStudio中会看到下面这张表格:

         这里就是app当前运行时的各项数据,其中:

               CPU:就是当前app占用的CPU百分比;

               MEMORY:就是当前app占用的内存大小;

               NETWORK:就是当前app使用的网络流量;

         点击MEMORY下的区域,会看到到内存的详细使用情况,这里重点说下内存使用页面的各项功能:          android Profiler 实战-----内存泄露的分析与定位_第1张图片

       1)、用于强制执行垃圾回收的按钮,也就是GC;

       2)、dump按钮,用以捕获堆转储,点击后会在捕捉接下来几秒中里内存中的所有对象及调用关系(经常用到);

             详细介绍:https://developer.android.com/studio/profile/memory-profiler#capture-heap-dump;

       3)、查看内存分配情况,此按钮仅在连接至运行 Android 7.1 或更低版本的设备时才会显示;

       4)、用于放大/缩小时间线的按钮;

       5)、用于跳转至实时内存数据的按钮;

       6)、Event 时间线,其显示 Activity 状态、用户输入 Event 和屏幕旋转 Event;

       7)、内存使用量时间线,其包含以下内容:

                    a.一个显示每个内存类别使用多少内存的堆叠图表,如左侧的 y 轴以及顶部的彩色键所示。

                    b.虚线表示分配的对象数,如右侧的 y 轴所示。

                    c.用于表示每个垃圾回收 Event 的图标。

       备注:Android 8.0 以上可以看到全部信息,8.0以下默认不是所有数据可见,需要启用高级分析才能查看以下内容:
                      * Event 时间线
                      * 分配的对象数
                      * 垃圾回收 Event

    3、内存计数中的类别如下所示

  • Java:从 Java 或 Kotlin 代码分配的对象内存。

  • Native:从 C 或 C++ 代码分配的对象内存。

    即使您的应用中不使用 C++,您也可能会看到此处使用的一些原生内存,因为 Android 框架使用原生内存代表您处理各种任务,如处理图像资源和其他图形时,即使您编写的代码采用 Java 或 Kotlin 语言。

  • Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。 (请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)

  • Stack: 您的应用中的原生堆栈和 Java 堆栈使用的内存。 这通常与您的应用运行多少线程有关。

  • Code:您的应用用于处理代码和资源(如 dex 字节码、已优化或已编译的 dex 码、.so 库和字体)的内存。

  • Other:您的应用使用的系统不确定如何分类的内存。

  • Allocated:您的应用分配的 Java/Kotlin 对象数。 它没有计入 C 或 C++ 中分配的对象。

    当连接至运行 Android 7.1 及更低版本的设备时,此分配仅在 Memory Profiler 连接至您运行的应用时才开始计数。 因此,您开始分析之前分配的任何对象都不会被计入。 不过,Android 8.0 附带一个设备内置分析工具,该工具可记录所有分配,因此,在 Android 8.0 及更高版本上,此数字始终表示您的应用中待处理的 Java 对象总数。

        与以前的 Android Monitor 工具中的内存计数相比,新的 Memory Profiler 以不同的方式记录您的内存,因此,您的内存使用量现在看上去可能会更高些。 Memory Profiler 监控的类别更多,这会增加总的内存使用量,但如果您仅关心 Java 堆内存,则“Java”项的数字应与以前工具中的数值相似。

         然而,Java 数字可能与您在 Android Monitor 中看到的数字并非完全相同,这是因为应用的 Java 堆是从 Zygote 启动的,而新数字则计入了为它分配的所有物理内存页面。 因此,它可以准确反映您的应用实际使用了多少物理内存。

         目前,Memory Profiler 还会显示应用中的一些误报的原生内存使用量,而这些内存实际上是分析工具使用的。 对于大约 100000 个对象,最多会使报告的内存使用量增加 10MB。 在这些工具的未来版本中,这些数字将从您的数据中过滤掉。

三、内存泄露的分析流程

       1、如何在Profiler中判断是否发生了内存泄露

              app使用过程中,打开一个页面,使用一段时间后,内存占用会上升,当关闭页面时,等待一段时间,内存占用没有下降或下降不明显,手动触发GC,dump栈中对象分配及调用关系,发现已关闭的页面或页面中原本该回收的对象仍存在,即可认为发生了内存泄露。

       2、举个例子。

            项目app中有一个拍照页面,拍照完照片会存储在本地,发现每次拍照完,内存都增加40M左右,而且拍照页面关闭后,内存占用仍高居不下,怀疑有内存泄露,分析流程如下:

            2.1:启动Profiler,app中打开拍照页面,拍照,关闭拍照页面,app占用内存如下:

android Profiler 实战-----内存泄露的分析与定位_第2张图片

        2.2:手动触发GC,然后点击dump按钮,将栈中的对象dump出来,dump完成后,看到内存中所有对象的占用数据。

android Profiler 实战-----内存泄露的分析与定位_第3张图片

        2.3: Heap Dump导航条中,当前显示分类是Arrange by class,按类名,也可以选择按包名和回调栈查看,同时最右方有一个漏斗,可以筛选指定的显示数据。当前按包名过滤、显示:

       android Profiler 实战-----内存泄露的分析与定位_第4张图片

        可以看到,拍照页面(SnapActivity)仍然存在,可以认为,这个页面发生了内存泄露,那是哪里泄露了呢?

        2.4 点击SnapActivity,可以看到SnapActivity中各对象的占用大小和调用关系,发现mPictureManager占用的内存最大,点开它之后发现里面有个callBack的对象指向了SnapActivity,会不会是这个callback引发了泄露呢?             android Profiler 实战-----内存泄露的分析与定位_第5张图片

       查看代码后发现,PictureManager是一个第三方库,使用时会设置一个callback用以接收拍照后的数据处理。它是一个单例模式的类,但它的单例是这么写的:

        static final 。。。也就意味着,给它设置callback后,这个callback会一直存在!!但拍照页面退出后并没有把callback置空,SnapActivity无法回收,导致了内存泄露。

        处理办法:由于这是个第三方库,无法修改源码,所以在拍照页面的onDestroy中,将PictureManager的callback置空。避免了内存泄露。            

        

     

 

 

 

 

你可能感兴趣的:(android)