Android Profiler
在新版的 Android studio 中, Profiler 的界面发生了变化,如下图所示。

其中:
- System Trace:显示整个系统的活动和资源使用情况。比如:应用和系统进程在设备核心和线程中的分布情况;界面渲染的流畅程度;设备和应用级别的耗电量
- Heap Dump:用于收集和分析堆转储,一般使用这个来分析内存
- Callstacks Sample:对调用堆栈进行抽样,可以在这里找到调用时间比较长的代码段
- Java/Kotlin Allocations:记录 Java/Kotlin 分配。比如:分配了哪些类型的对象以及它们使用多少空间;每个分配的堆栈轨迹,包括在哪个线程中。
- Java/Kotlin Method Recording:记录应用代码执行期间调用的 Java/Kotlin 方法,可让我们查看特定时间点的调用堆栈和 CPU 使用情况(已过滤为仅显示 Java/Kotlin 方法)。此数据有助于识别执行时间长或消耗大量系统资源的代码段。
- Native Allocations:原生代码表示的对象的分配和解除分配情况
- View Live Telemetry: 用于实时检查应用,可以大致了解设备的 CPU 使用情况、线程活动和内存使用情况。
这篇文章将介绍新版 Profiler 中,Heap Dump 的使用
Heap Dump
启动 Heap Dump 分析后,可以捕获当前的内存中所有对象的快照,如下图所示:

注意:在转储堆期间,Java 内存量可能会临时性增加。这是因为堆转储需要一些内存来收集数据。
下拉菜单
Heap Dump 界面的第一行有三个下拉菜单,其作用分别是:过滤特定的堆 、内存分配排列方式 、 指定 Class。
过滤特定的堆
如下图所示:

- View all heaps:查看所有堆
- View app heap(默认):查看 App 在其中分配内存的主堆
- View image heap:系统启动映像,包含启动期间预加载的类,此处的分配确保绝不会移动或消失
- View zygote heap:写时复制堆,其中的应用进程是从 Android 系统中派生的
内存分配排列方式
如下图所示:

- Arrange by class(默认):默认根据类名对所有分配进行分组
- Arrange by package:根据软件包名对所有分配进行分组
过滤 Class
如下图所示:

- Show all classes(默认):显示所有类,包括库中的类 和依赖项
- Show activity/fragment Leaks:展示泄露的 Activity/Fragment
- Show project class:仅显示项目定义的类
类列表
设置好第一行的下拉菜单后,我们就可以在类列表中查看对应的内存使用情况。这里以 过滤 Class 设置为 Show project class 为例,如下图所示:

可以看到其中:
- Classes:指类的种类
- Leaks:展示泄露数量,双击会自动选中 Show activity/fragment Leaks
- Count:堆中对象的分配数量
- Native Size:此对象类型使用的原生内存总量(单位字节)
- Shallow Size:指的是对象实例自身占用的内存大小,不包括它引用的其他对象的内存。(单位字节)
- Retained Size :是该对象及其独占引用的其他对象(基于支配树 dominator tree)的总内存大小(单位字节)
注意:Native Size 只有在使用 Android 7.0 及更高版本时,才会看到此列,会在此处看到采用 Java 分配的某些对象的内存,因为 Android 对某些框架类(如 Bitmap)使用原生内存
假设对象的依赖关系如下图所示,此时
css
Shallow Size = size(A)
// 由于对象 B 只被对象A引用,如果对象A被回收,那么对象B也会被回收
Retained Size = size(A) + size(B)

如果 B 对象被其他对象引用,则此时
txt
Shallow Size = size(A)
// 由于对象 B 同时被对象A和对象C引用,如果对象A被回收,那么对象C不会被回收
Retained Size = size(A)

更多关于 Shallow Size & Retained Size 具体可以看 Android优化篇|Shallow Size & Retained Size

上图所示,是具体的类所占用的内存。其中 Allocations 是指堆中的对象的分配数,和 Count 是相同的。
注意,Retained Size 一定是大于或者等于 Shallow Size 的。在 heap dump 的界面中,有时候会出现 Retained Size 小于 Shallow Size 的情况,这可能是 Android studio 的bug,具体可以看 issuetracker.google.com/issues/2820...
内存泄漏
点击 Leaks 或者选择 Show activity/fragment Leaks 可以展示内存泄漏界面,如下图所示:

如下图所示,对于 LeakActivity 对象,其中 Depth 是指从任意 GC 根到选定实例的最短跳数。

点击泄漏的 LeakActivity 对象,可以看到该对象的实例详情,如下所示。

其中:
- Fields:显示此实例中的所有字段。
- References:显示对 Instance 标签页中突出显示的对象的每个引用。
对于内存泄漏的排查,一般我们需要选中 Show nearest GC root only,显示最近的 GC root。通过这个来排查哪里还在引用该 Activity 或者 Fragment。
注意:在以下情况中可能会产生误报的问题:
- 已创建
Fragment
,但尚未使用它。- 正在缓存
Fragment
,但它不是FragmentTransaction
的一部分
由于在此界面,无法直接强制触发 GC,我们需要通过以下方式来实现类似的效果:
- 将设备从竖屏旋转为横屏,然后反复旋转多次 在不同 activity 状态下使用。
- 当处于不同的 activity 状态时,在我们的应用与其他应用之间切换。 例如,导航到主屏幕,然后返回我们的应用。