Android内存分析工具:Memory Profiler
2018-01-11 11:04
543 查看
一、前言
我们知道,Android系统检测到app有不再使用对象时,就会进行内存回收相关的工作。
尽管Android检测无用对象、回收内存的方法在不断改进,
但在目前所有的Android版本中,进行上述工作时,系统仍需要短暂地停止app的运行。
在大多数情况下,系统进行内存回收的行为是无法被用户察觉到的。
然而,如果应用分配内存的速度大于系统回收的速度,
那么app进程的正常运行可能就回受到影响。
毕竟,系统必须回收到足够的供app需要的内存,才会恢复处于暂停状态的app。
在这种情况下,app就可能出现掉帧、卡顿等现象。
在更严重的情况下,如果出现了内存泄露的问题,那么系统中就可能堆积无法释放的内存,
使得系统必须更加频繁地进行内存回收,从而降低系统的性能。
甚至在极端条件下,系统不得不杀死部分正在后台运行的app进程。
于是用户将后台应用移到前台时,却发现应用无故重启,这显然带来了较差的用户体验。
由此可见,内存对于app而言,是极其关键的性能指标。
目前,分析app内存的工具有很多,
本文主要记录一下Android Studio内置的内存分析工具Memory Profiler。
二、基本介绍
Memory Profiler是Android Profiler的一个组件, 用于帮助分析内存泄露和内存抖动的问题。
当PC连接Android L以上的设备时,该工具才能够正常使用。
Memory Profiler的功能包括:
展示应用内存使用情况的实时图像、抓取内存的dump信息、强制垃圾回收及追踪内存分配。
2.1 开启步骤
打开Memory Profiler的步骤为:
1、 依次点击Android Studio的View → Tool Windows → Android Profiler,
或直接点击工具栏Android Profiler对应的图标;
2、 PC连接Android终端后,在Android Profiler对应的区域选择接的设备和需要监控的进程:
3、 点击Android Profiler界面中MEMORY区域的任意位置,即可开启Memory Profiler,如下图所示:
需要注意的是,如果PC连接Android 7.1以下的设备时,有些关键数据可能无法被Android Profiler统计,
此时Android Profiler会显示如下信息:
这时我们需要依次点击Android Studio的Run → Edit Configurations → Profiling 按键,选中app后点击Enabled advanced profiling,
如下图所示:
为了支持该功能,要求app对应的gradle版本必须在2.4以上。
2.2 界面介绍
打开Memory Profiler后,主界面如下所示(为了方便,这里直接盗取Android技术文档中的图):
其中:
标注1对应的按键用于强制内存回收。
标注2对应的按键用于抓取进程内存的dump信息。
标注3对应的按键用于记录内存的分配信息(连接Android 7.1及以下才会有此按键)。
初次点击时,对应统计的开始时间点;再次点击时,对应统计的结束时间点。
进程在两个时间点之间的内存分配信息,将被Memory Profiler记录和分析。
标注4对应的区域用于缩放时间轴。
标注5对应的按键用于显示实时的内存数据。
标注6对应的区域用于记录事件发生的时间点及大致持续的时间(例如activity状态改变、用户操作界面等事件)。
标注7对应的区域用于显示内存使用情况对应的时间轴(与标注6结合,就可以看出各事件带来的内存变化情况)。
需要说明的是,标注7对应区域显示的内容包括:
不同类型内存占用情况对应的图像;
分配对象数量对应的短画线;
内存回收事件发生的时机。
2.3 统计的数据类型及含义
Memory Profiler主要根据Android系统提供的信息,
统计app独自占用内存,即不统计app与系统或其它app共有的内存。
Memory Profiler统计内存的种类如下图所示:
如上图所示,其中:
Java表示Java代码或Kotlin代码分配的内存;
Native表示C或C++代码分配的内存(即使App没有native层,调用framework代码时,也有可能触发分配native内存);
Graphics表示图像相关缓存队列占用的内存;
Stack表示native和java占用的栈内存;
Code表示代码、资源文件、库文件等占用的内存;
Others表示无法明确分类的内存;
Allocated表示Java或Kotlin分配对象的数量(Android8.0以下时,仅统计Memory Profiler启动后,进程再分配的对象数量;
8.0以上时,由于系统内置了统计工具,Memory Profiler可以得到整个app启动后分配对象的数量)。
三、基本用法
对Memory Profiler有了基本的了解后,我们来看看它的基本用法。
3.1 查看内存分配情况
Memory Profiler可以查看两个时间点之间的内存分配情况,包括:
对象的类型、占用内存的大小、栈信息等。
连接8.0以上的设备时,Memory Profiler还可以显示对象被回收的时间。
PC连接8.0以上的设备时,在内存统计的时间线上,直接点击和拖动就可以选择观察区域;
连接低版本的设备时,则需要点击Record Memory allocations按键(2.2小结介绍的标注3)选择观察区域。
选定观察区域后, Memory Profiler就可以统计这段时间内app分配内存的情况:
从图中可以看出,Memory Profiler可以显示分配对象的类名;
点击类后,会在Instance View显示具体的对象;
点击具体对象后,会在Call back区域显示调用栈。
点击调用栈信息后,就会跳转到具体的代码。
3.2 查看内存占用情况
点击2.2小结介绍的标注2,即可抓取点击后一段时间内app占用内存的dump信息。
通过dump信息,我们可以看到app当前仍存在于内存中的对象。
结合代码,我们可以分析是否有本应被析构却仍存活的泄露对象。
与统计内存分配信息一样,内存占用信息同样会显示对象的类型、数量、占用内存的大小、引用关系等。
如下图所示:
图中Alloc Count表示堆中分配对象的数量;
Shallow Size表示对象使用Java内存的大小,单位为byte;
Retained Size表示对象占用的实际内存大小,大于等于Shallow Size;
7.0及以上版本的设备,还会显示对象占用的Native Size。
点击具体的对象时,也会显示Instance View。
此时,Instance View显示的信息变多了,包括:
Depth表示当前对象到任一GC root的最短跳数;
Shallow Size、Retained Size的含义与前文一致。
同样,7.0及以上版本的设备,还会显示对象占用的Native Size。
从图中可以看出,Instance View不会显示栈信息。
如果想获得栈信息的话,必须先点击Record Memory allocations按键。
四、使用示例
利用Memory Profiler,我分析了一下某反病毒引擎SDK的内存占用情况。
随便写了个demo,继承SDK后启动app,内存占用情况如下图所示:
然后,通过操作UI初始化SDK,发现稳定后内存占用情况如下图所示:
比对前后两图,不考虑界面UI变化消耗的内存,
可以看出:内存增加的主体部分来自于Native函数,其它类型的内存变化几乎可以忽略。
这是因为该SDK初始化时,最主要的工作是在Native层加载底层的so文件。
接下来,我们在demo里调用SDK的接口,批量扫描样本,统计内存消耗情况如下图所示:
从图中可以看出app消耗的内存飙升到了104M,
与初始化后的内存相比,其中增加主要是code和native类型的内存。
根据2.3小结的描述,我们知道code类型统计的是app进程需要的资源文件、库文件等,
因此这部分内存主要是SDK中引擎加载病毒库等消耗掉的内存;
而Native内存的消耗,应该也是由于引擎扫描文件导致的。
按照3.1小结的描述,我们查看了一下批量扫描这段时间内,
app进程内存分配的情况,如下图所示:
容易看出,在这段时间内,除去native内存外,整个app分配内存并不大,
且按照对象占用内存的大小排序,排在前列的都是基本数据类型。
因此,这段时间内app进程的内存应该是比较正常的。
我们进行GC操作,内存情况如下图所示:
发现内存几乎和扫描前一致,按照3.2小结进行dump分析,没有发现泄露对象。
因此,可以确认SDK不存在内存泄露的问题(dump信息含有sdk的隐私,这里就不再附图了)。
五、总结
至此,我们已经介绍了Android Memory Profiler工具的基本情况,
并简单列举了该工具的使用方式。
个人感觉,不同于LeakCanary,
Android Memory Profiler更侧重于宏观场景下的内存分析。
我们知道,Android系统检测到app有不再使用对象时,就会进行内存回收相关的工作。
尽管Android检测无用对象、回收内存的方法在不断改进,
但在目前所有的Android版本中,进行上述工作时,系统仍需要短暂地停止app的运行。
在大多数情况下,系统进行内存回收的行为是无法被用户察觉到的。
然而,如果应用分配内存的速度大于系统回收的速度,
那么app进程的正常运行可能就回受到影响。
毕竟,系统必须回收到足够的供app需要的内存,才会恢复处于暂停状态的app。
在这种情况下,app就可能出现掉帧、卡顿等现象。
在更严重的情况下,如果出现了内存泄露的问题,那么系统中就可能堆积无法释放的内存,
使得系统必须更加频繁地进行内存回收,从而降低系统的性能。
甚至在极端条件下,系统不得不杀死部分正在后台运行的app进程。
于是用户将后台应用移到前台时,却发现应用无故重启,这显然带来了较差的用户体验。
由此可见,内存对于app而言,是极其关键的性能指标。
目前,分析app内存的工具有很多,
本文主要记录一下Android Studio内置的内存分析工具Memory Profiler。
二、基本介绍
Memory Profiler是Android Profiler的一个组件, 用于帮助分析内存泄露和内存抖动的问题。
当PC连接Android L以上的设备时,该工具才能够正常使用。
Memory Profiler的功能包括:
展示应用内存使用情况的实时图像、抓取内存的dump信息、强制垃圾回收及追踪内存分配。
2.1 开启步骤
打开Memory Profiler的步骤为:
1、 依次点击Android Studio的View → Tool Windows → Android Profiler,
或直接点击工具栏Android Profiler对应的图标;
2、 PC连接Android终端后,在Android Profiler对应的区域选择接的设备和需要监控的进程:
3、 点击Android Profiler界面中MEMORY区域的任意位置,即可开启Memory Profiler,如下图所示:
需要注意的是,如果PC连接Android 7.1以下的设备时,有些关键数据可能无法被Android Profiler统计,
此时Android Profiler会显示如下信息:
这时我们需要依次点击Android Studio的Run → Edit Configurations → Profiling 按键,选中app后点击Enabled advanced profiling,
如下图所示:
为了支持该功能,要求app对应的gradle版本必须在2.4以上。
2.2 界面介绍
打开Memory Profiler后,主界面如下所示(为了方便,这里直接盗取Android技术文档中的图):
其中:
标注1对应的按键用于强制内存回收。
标注2对应的按键用于抓取进程内存的dump信息。
标注3对应的按键用于记录内存的分配信息(连接Android 7.1及以下才会有此按键)。
初次点击时,对应统计的开始时间点;再次点击时,对应统计的结束时间点。
进程在两个时间点之间的内存分配信息,将被Memory Profiler记录和分析。
标注4对应的区域用于缩放时间轴。
标注5对应的按键用于显示实时的内存数据。
标注6对应的区域用于记录事件发生的时间点及大致持续的时间(例如activity状态改变、用户操作界面等事件)。
标注7对应的区域用于显示内存使用情况对应的时间轴(与标注6结合,就可以看出各事件带来的内存变化情况)。
需要说明的是,标注7对应区域显示的内容包括:
不同类型内存占用情况对应的图像;
分配对象数量对应的短画线;
内存回收事件发生的时机。
2.3 统计的数据类型及含义
Memory Profiler主要根据Android系统提供的信息,
统计app独自占用内存,即不统计app与系统或其它app共有的内存。
Memory Profiler统计内存的种类如下图所示:
如上图所示,其中:
Java表示Java代码或Kotlin代码分配的内存;
Native表示C或C++代码分配的内存(即使App没有native层,调用framework代码时,也有可能触发分配native内存);
Graphics表示图像相关缓存队列占用的内存;
Stack表示native和java占用的栈内存;
Code表示代码、资源文件、库文件等占用的内存;
Others表示无法明确分类的内存;
Allocated表示Java或Kotlin分配对象的数量(Android8.0以下时,仅统计Memory Profiler启动后,进程再分配的对象数量;
8.0以上时,由于系统内置了统计工具,Memory Profiler可以得到整个app启动后分配对象的数量)。
三、基本用法
对Memory Profiler有了基本的了解后,我们来看看它的基本用法。
3.1 查看内存分配情况
Memory Profiler可以查看两个时间点之间的内存分配情况,包括:
对象的类型、占用内存的大小、栈信息等。
连接8.0以上的设备时,Memory Profiler还可以显示对象被回收的时间。
PC连接8.0以上的设备时,在内存统计的时间线上,直接点击和拖动就可以选择观察区域;
连接低版本的设备时,则需要点击Record Memory allocations按键(2.2小结介绍的标注3)选择观察区域。
选定观察区域后, Memory Profiler就可以统计这段时间内app分配内存的情况:
从图中可以看出,Memory Profiler可以显示分配对象的类名;
点击类后,会在Instance View显示具体的对象;
点击具体对象后,会在Call back区域显示调用栈。
点击调用栈信息后,就会跳转到具体的代码。
3.2 查看内存占用情况
点击2.2小结介绍的标注2,即可抓取点击后一段时间内app占用内存的dump信息。
通过dump信息,我们可以看到app当前仍存在于内存中的对象。
结合代码,我们可以分析是否有本应被析构却仍存活的泄露对象。
与统计内存分配信息一样,内存占用信息同样会显示对象的类型、数量、占用内存的大小、引用关系等。
如下图所示:
图中Alloc Count表示堆中分配对象的数量;
Shallow Size表示对象使用Java内存的大小,单位为byte;
Retained Size表示对象占用的实际内存大小,大于等于Shallow Size;
7.0及以上版本的设备,还会显示对象占用的Native Size。
点击具体的对象时,也会显示Instance View。
此时,Instance View显示的信息变多了,包括:
Depth表示当前对象到任一GC root的最短跳数;
Shallow Size、Retained Size的含义与前文一致。
同样,7.0及以上版本的设备,还会显示对象占用的Native Size。
从图中可以看出,Instance View不会显示栈信息。
如果想获得栈信息的话,必须先点击Record Memory allocations按键。
四、使用示例
利用Memory Profiler,我分析了一下某反病毒引擎SDK的内存占用情况。
随便写了个demo,继承SDK后启动app,内存占用情况如下图所示:
然后,通过操作UI初始化SDK,发现稳定后内存占用情况如下图所示:
比对前后两图,不考虑界面UI变化消耗的内存,
可以看出:内存增加的主体部分来自于Native函数,其它类型的内存变化几乎可以忽略。
这是因为该SDK初始化时,最主要的工作是在Native层加载底层的so文件。
接下来,我们在demo里调用SDK的接口,批量扫描样本,统计内存消耗情况如下图所示:
从图中可以看出app消耗的内存飙升到了104M,
与初始化后的内存相比,其中增加主要是code和native类型的内存。
根据2.3小结的描述,我们知道code类型统计的是app进程需要的资源文件、库文件等,
因此这部分内存主要是SDK中引擎加载病毒库等消耗掉的内存;
而Native内存的消耗,应该也是由于引擎扫描文件导致的。
按照3.1小结的描述,我们查看了一下批量扫描这段时间内,
app进程内存分配的情况,如下图所示:
容易看出,在这段时间内,除去native内存外,整个app分配内存并不大,
且按照对象占用内存的大小排序,排在前列的都是基本数据类型。
因此,这段时间内app进程的内存应该是比较正常的。
我们进行GC操作,内存情况如下图所示:
发现内存几乎和扫描前一致,按照3.2小结进行dump分析,没有发现泄露对象。
因此,可以确认SDK不存在内存泄露的问题(dump信息含有sdk的隐私,这里就不再附图了)。
五、总结
至此,我们已经介绍了Android Memory Profiler工具的基本情况,
并简单列举了该工具的使用方式。
个人感觉,不同于LeakCanary,
Android Memory Profiler更侧重于宏观场景下的内存分析。
相关文章推荐
- Android内存分析工具:Memory Profiler
- [原创]推荐一款强大的.NET程序内存分析工具.NET Memory Profiler
- 使用ANTS Performance Profiler&ANTS Memory Profiler工具分析IIS进程内存和CPU占用过高问题
- Android 内存分析工具 MAT(Memory Analyzer Tool)
- 使用ANTS Performance Profiler&ANTS Memory Profiler工具分析IIS进程内存和CPU占用过高问题
- [Android Memory] 内存分析工具 MAT 的使用
- Android 内存分析工具 MAT(Memory Analyzer Tool)
- Unity5.3a4新版内存分析工具 -MemoryProfiler
- [Android Memory] 内存分析工具 MAT 的使用
- Android 内存分析工具 MAT(Memory Analyzer Tool)(转)
- Unity5.3a4新版内存分析工具 -MemoryProfiler
- Android 内存分析工具MemoryAnalizer
- Unity5.3a4新版内存分析工具 -MemoryProfiler
- [Android Memory] 内存分析工具 MAT 的使用
- [Android Memory] 内存分析工具 MAT 的使用
- [Android Memory] 内存分析工具 MAT 的使用
- Android内存分析工具(六):开源项目Emmagee
- Android 内存分析工具LogCat GC
- Android性能优化之内存泄漏分析工具LeakCanary
- 【测试工具】Android内存分析工具 MAT 的安装