上一篇讲了使用LeakCanary检测和分析内存泄漏
LeakCanary作为一个开源库,还是很好用的
但其实我们Android Studio也提供了内存检测工具
它的名字叫做Memory Profiler。
这篇博客就带大家来认识它
首先我们来看怎么打开Memory Profiler
在Android Studio中有两种方式打开Memory Profiler
第一种通过标题栏打开,如图所示
第二种通过下方菜单栏打开,如图所示
使用的话也很简单,首先运行起你的项目
然后点击Profiler窗口左上角的 + 号
选择你项目的包名
选择完成后,就会创建你项目的SESSIONS界面,如下图
当然,有时候AS会默认给你创建这个包名的SESSIONS
如果你想删除这个SESSIONS,右键删除即可
下面开始介绍如何进行内存分析
点击MEMORY进入到内存分析,界面如下:
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按钮
进入到如下界面:
按照图里的顺序,最后点击Jump to Source
可以定位到大概的泄漏代码位置
当然,和LeakCanary一样
Memory Profiler也不是能定位到所有的泄漏
比如,如果你怀疑一个Activity泄漏
你可以通过上面界面的Class列表
查看这个Activity在内存中的个数,
如果退出后个数并未减少,说明存在泄漏
可以继续按照上图的方式定位问题。
在Class列表里,点击Class Name可以对这些Class按照类名排序
如下图所示
Class Name:类名
Alloc Count:对象个数
Native Size:c/c++层内存大小(byte)
Shallow Size:java层内存大小(bytes)
Retained Size:这个是这个类中所引用到的对象的总大小*该类对象的个数
关于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成功分析、定位、修复了这个内存泄漏
Profiler窗口里的MEMORY运行久了
这时候再进行内存分析,AS可能会出现卡死的情况
可能是需要分析的文件太多导致的
这时候可以先右键删除SEESIONS下的这个项目
然后重新添加进来即可
内存泄漏的定位和分析
可以用Memory Profiler和LeakCanary两个工具互相验证
两个软件各有利弊
互相验证能让我们更好的确保内存泄漏问题的复现和解决