(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用

前言

上一篇讲了使用LeakCanary检测和分析内存泄漏

LeakCanary作为一个开源库,还是很好用的

但其实我们Android Studio也提供了内存检测工具

它的名字叫做Memory Profiler。

这篇博客就带大家来认识它

Memory Profiler使用

首先我们来看怎么打开Memory Profiler

在Android Studio中有两种方式打开Memory Profiler

第一种通过标题栏打开,如图所示
(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第1张图片
第二种通过下方菜单栏打开,如图所示
(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第2张图片
使用的话也很简单,首先运行起你的项目

然后点击Profiler窗口左上角的 + 号

选择你项目的包名

(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第3张图片
选择完成后,就会创建你项目的SESSIONS界面,如下图
(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第4张图片
当然,有时候AS会默认给你创建这个包名的SESSIONS

如果你想删除这个SESSIONS,右键删除即可

下面开始介绍如何进行内存分析

点击MEMORY进入到内存分析,界面如下:

(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第5张图片

1:强制调用GC进行内存回收

2:Dump the java heap

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

4: 实时播放内存分配情况

5: 发生一些事件的记录(如Activity跳转,事件的输入、屏幕的旋转)

6: 放大/缩小时间线

7: 使用的内存时间线

8: 退出MEMORY,回到SESSIONS主界面

关于顶部的几种内存类型介绍

Java:java代码分配的内存

Native:c/c++代码分配的内存(有时候其实并没有使用c/c++代码,但还是会有Native的内存分配,因为Android Framework会去通过java代码访问一些需要使用Native的资源,如图像资源的Bitmap)

Graphics:图像缓存等,包括GL surfaces,GL textures等

Stack:栈内存(包括java和c/c++)

Code:代码的内存分配(例如代码,资源,libs等等)

Other:这个是系统都不知道什么类型的内存

Allocated:java分配的对象个数

点击一个时间线上的节点,然后点击Dump the java heap按钮

进入到如下界面:

(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第6张图片
可以看到提示有四个内存泄漏

按照图里的顺序,最后点击Jump to Source

可以定位到大概的泄漏代码位置

当然,和LeakCanary一样

Memory Profiler也不是能定位到所有的泄漏

比如,如果你怀疑一个Activity泄漏

你可以通过上面界面的Class列表

查看这个Activity在内存中的个数,

如果退出后个数并未减少,说明存在泄漏

可以继续按照上图的方式定位问题。

在Class列表里,点击Class Name可以对这些Class按照类名排序

如下图所示

(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第7张图片
在图片中可以看到如下列

Class Name:类名

Alloc Count:对象个数

Native Size:c/c++层内存大小(byte)

Shallow Size:java层内存大小(bytes)

Retained Size:这个是这个类中所引用到的对象的总大小*该类对象的个数

关于Memory Profiler的使用就介绍到这里,下面看一个实战小例子

Memory Profiler实战小例子

我们先来看这一段代码


class MainActivity2 : AppCompatActivity() {
 
    lateinit var myHandler: MyHandler
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        //传入activity对象
        myHandler = MyHandler(this)
        myHandler.postDelayed(Runnable {
            Log.d("MainActivity2", "十分钟后日志打印")
        }, 0x001, 1000 * 60 * 10)
 
    }
 
    class MyHandler(var mainContext: MainActivity2) : Handler() {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
        }
    }
 
}

运行这个代码,然后利用Memory Profiler进行分析

发现存在内存泄漏,并且定位到代码位置


class MyHandler(var mainContext: MainActivity2) : Handler() {
    override fun handleMessage(msg: Message) {
        super.handleMessage(msg)
    }
}

因为代码里这个Handler有延时操作,在Activity退出后还持有了Activity对象的引用

所以存在内存泄漏

我们只需要在onDestroy方法里移除延时任务,即可修复这个泄漏

override fun onDestroy() {
    super.onDestroy()
    myHandler.removeCallbacksAndMessages(0x001)
}

这样,我们就通过Memory Profiler成功分析、定位、修复了这个内存泄漏

Memory Profiler注意事项

Profiler窗口里的MEMORY运行久了

这时候再进行内存分析,AS可能会出现卡死的情况

可能是需要分析的文件太多导致的

这时候可以先右键删除SEESIONS下的这个项目

然后重新添加进来即可

不影响内存分析的结果
(原创)内存泄漏分析解决方案(三):Memory Profiler介绍和使用_第8张图片
最后还有个小Tip

内存泄漏的定位和分析

可以用Memory Profiler和LeakCanary两个工具互相验证

两个软件各有利弊

互相验证能让我们更好的确保内存泄漏问题的复现和解决

你可能感兴趣的:(Android开发,android,android,studio,java)