乐趣区

关于android-studio:使用-Android-Studio-Profiler-工具解析应用的内存和-CPU-使用数据

为了帮忙开发者开发出更加轻快高效的利用,咱们在 Android Studio 3.0 以及更高版本中退出了 Android Profiler 工具,用于利用的 CPU、内存、网络和能耗剖析。

在 Android Profiler 提供的这四种性能数据中,绝大多数场景下咱们都更关怀 CPU 和内存的应用状况。本文将介绍对应的两种剖析工具 —— Memory Profiler 和 CPU Profiler。

Memory Profiler

许多开发者应用 Memory Profiler,是心愿发现和定位内存透露问题。在介绍 Memory Profile 如何解决这一问题之前,我想先明确 “ 内存透露 ” 这一概念。无论您以后是否理解内存透露,都将帮忙我更好地解释 Memory Profile 的工作原理。

内存透露

什么是内存透露?

通常咱们认为,在运行的程序中,如果一个无法访问的对象却依然占用着内存空间,即为此对象造成了内存透露。如果您应用过 C 语言或 C++ 的指针,您会很相熟这个概念。

然而在 Kotlin 和 Java 的世界中,事件有些许不同。因为这两种语言是运行在 Java 虚拟机 (JVM) 中的。在 JVM 中,有个重要的概念,就是垃圾回收 (GC)。当垃圾回收运行时,虚构机会首先辨认 GC Root。GC Root 是一个能够从堆内部拜访的对象,它能够是本地变量或运行中的线程等。虚构机会辨认所有能够从 GC Root 拜访的对象,它们将会被保留。而其余无奈从 GC root 拜访的对象,则会被认为是垃圾并回收掉。

所以,个别意义上的内存透露在 JVM 中并不存在。在 JVM 中的内存透露通常是指: 内存中含有那些再也不会被应用、然而依然可能拜访的对象。

Activity 和 Fragment 透露检测

在 Android 利用中,该当尤为警觉 Activity 和 Fragment 对象的透露,因为这两种对象通常都会占用很多内存。在 Android 3.6 中,Memory Profiler 退出了主动查看 Activity 和 Fragment 中的内存透露的性能。应用这一性能十分的简略:

  • 首先,您须要在 Memory Profiler 中保留 Heap Dump,点击下图所示按钮:

  • 在 Heap Dump 加载实现后,勾选 “Activity/Fragment Leaks” 选框:

此时如果有查看到 Activity 或 Fragment 的透露,就会在界面中显示进去。

Memory Profiler 通过以下几种场景来判断透露是否产生:

  • 当咱们销毁了一个 Activity 的实例后,这个实例就再也不会被应用了。此时如果依然有这个 Activity 的援用,Memory Profiler 就会认为它曾经透露;
  • Fragment 的实例该当与一个 Fragment Manager 相关联,如果咱们看到一个 Fragment 没有关联任何一个 Fragment Manager,而且它仍然被援用时,也能够认为有透露产生。

不过要留神的是,针对 Fragment 有个特地的状况: 如果您载入的 Heap Dump 的机会,刚好介于 Fragment 被创立和被应用的工夫之间,就会造成 Memory Profiler 误报;雷同状况也会产生在 Fragment 被缓存然而没有被复用的时候。

其余内存透露检测

Memory Profiler 也能够用于查看其余类型的透露,它提供了许多信息,用于帮忙您辨认内存透露是否产生。

当您拿到一段 Heap Dump 之后,Memory Profiler 会展现出类的列表。对于每个类,”Allocation” 这一列显示的是它的实例数量。而在它左边则顺次是 “Native Size”、”Shallow Size” 和 “Retained Size”:

这几组数据别离意味着什么呢?上面我会通过一个例子来阐明。

咱们用下图来示意某段 Heap Dump 记录的利用内存状态。留神红色的节点,在这个示例中,这个节点所代表的对象从咱们的工程中援用了 Native 对象:

这种状况不太常见,但在 Android 8.0 之后,应用 Bitmap 便可能产生此类情景,因为 Bitmap 会把像素信息存储在原生内存中来缩小 JVM 的内存压力。

先从 “Shallow Size” 讲起,这列数据其实非常简单,就是对象自身耗费的内存大小,在上图中,即为红色节点本身所占内存。

而 “Native Size” 同样也很简略,它是类对象所援用的 Native 对象 (蓝色节点) 所耗费的内存大小:

“Retained Size” 稍简单些,它是下图中所有橙色节点的大小:

因为一旦删除红色节点,其余的橙色节点都将无奈被拜访,这时候它们就会被 GC 回收掉。从这个角度上讲,它们是被红色节点所持有的,因而被命名为 “Retained Size”。

还有一个后面没有提到的数据维度。当您点击某个类名,界面中会显示这个类实例列表,这里有一列新数据 —— “Depth”:

“Depth” 是从 GC Root 达到这个实例的最短门路,图中的这些数字就是每个对象的深度 (Depth):

一个对象离 GC Root 越近,它就越有可能与 GC Root 有多条门路相连,也就越可能在垃圾回收中被保留下来。

以红色节点为例,如果从其右边来的任何一个援用被毁坏,红色节点就会变成不可拜访的状态并且被垃圾回收回收掉。而对于左边的蓝色节点来说,如果您心愿它被垃圾回收,那您须要把左右两边的门路都毁坏才行。

值得警觉的是,如果您看到某个实例的 “Depth” 为 1 的话,这意味着它间接被 GC root 援用,同时也意味着它永远不会被主动回收。

上面是一个示例 Activity,它实现了 LocationListener 接口,高亮局部代码 “requestLocationUpdates” 将会应用以后 Activity 实例来注册 locationManager。如果您遗记登记,这个 Activity 就会透露。它将永远都待在内存里,因为地位管理器是一个 GC root,而且永远都存在:

您能在 Memory Profiler 中查看这一状况。点击一个实例,Memory Profiler 将会关上一个面板来显示谁正在援用这个实例:

咱们能够看到地位管理器中的 mListener 正在援用这个 Activity。您能够更进一步,通过援用面板导航至堆的援用视图,它能够让您验证这条援用链是否是您所预期的,也能帮您了解代码中是否有透露以及哪里有透露。

CPU Profiler

和 Memory Profiler 相似,CPU Profiler 提供了从另一个角度记录和剖析利用要害性能数据的办法。

应用 CPU Profiler,首先要产生一些 CPU 的应用记录:

  • 进入 Android Studio 中的 CPU Profiler 界面,在您的利用曾经部署的前提下,点击 “Record” 按钮;
  • 在利用中进行您想要剖析的操作;
  • 返回 CPU Profiler,点击 “Stop” 按钮。

因为最终出现的数据是基于线程组织的,所以去察看数据之前,您应该确认是否抉择了正确的线程:

咱们这里所取得的 CPU 应用记录信息,其实是一个 System Trace 实例的调用栈汇合 (下文统称 “ 调用栈 ”)。而就算是很短的 CPU 应用记录,也会蕴含巨量的信息,同时这些信息也是人无奈读懂的。所以 CPU Profiler 提供了一些工具来可视化这些数据。

Call Chart

在 CPU Profiler 界面下半部,有四个标签页,别离对应四个不同的数据图表,它们别离是: Call Chart、Flame Chart、Top Down 和 Bottom Up。其中的 Call Chart 可能是最直白的一个,它基本上就是一个调用栈的从新组织和可视化出现:

Call Chart 横轴就是工夫线,用来展现办法开始与完结的确切工夫,纵轴则自上而下展现了办法间调用和被调用的关系。Call Chart 曾经比原数据可读性高很多,但它依然不不便发现那些运行工夫很长的代码,这时咱们便须要应用 Flame Chart。

Flame Chart

Flame Chart 提供了一个调用栈的聚合信息。与 Call Chart 不同的是,它的横轴显示的是百分比数值。因为疏忽了工夫线信息,Flame Chart 能够展现每次调用耗费工夫占用整个记录时长的百分比。同时纵轴也被对调了,在顶部展现的是被调用者,底部展现的是调用者。此时的图表看起来越往上越窄,就如同火焰一样,因而得名:

Flame Chart 是基于 Call Chart 来从新组织信息的。从 Call Chat 开始,合并雷同的调用栈,以耗时由长至短对调用栈进行排序,就取得了 Flame Chart:

比照两种图表不难看出,右边的 Call Chart 有具体的工夫信息,能够展现每次调用是何时产生的;左边的 Flame Chart 所展现的聚合信息,则有助于发现一个总耗时很长的调用门路:

Top Down Tree

后面介绍的两种图表,能够帮忙咱们从两种角度纵览全局。而如果咱们须要更准确的工夫信息,就须要应用 Top Down Tree。在 CPU Profiler 中,Top Down 选项卡展现的是一个数据表格,为了便于了解其中各组数据的意义,接下来咱们会尝试构建一个 Top Down Tree。

构建一个 Top Down Tree 并不简单。以 Flame Chart 为根底,您只须要从调用者开始,继续增加被调用者作为子节点,直到整个 Flame Chart 被遍历一遍,您就取得了一个 Top Down Tree:

对于每个节点,咱们关注三个工夫信息:

  • Self Time —— 运行本人的代码所耗费的工夫;
  • Children Time —— 调用其余办法的工夫;
  • Total Time —— 后面两者工夫之和。

有了 Top Down Tree,咱们能轻易将这三组信息归纳到一个表格之中:

上面咱们来看一看这些工夫信息是怎么计算的。左手边是和后面一样的 Flame Chart 示例。左边则是一个 Top Down Tree。

咱们从 A 节点开始:

  • A 耗费了 1 秒钟来运行本人的代码,所以 Self Time 是 1;
  • 而后它耗费了 9 秒中去调用其余办法,这意味着它的 Children Time 是 9;
  • 这样就一共耗费了 10 秒钟,Total Time 是 10;
  • B 和 D 以此类推 …

值得注意的是,D 节点只是调用了 C,本人没做任何事,这种状况在办法封装时很常见。所以 D 的 Children Time 和 Total Time 都是 2。

上面是表格齐全开展的状态。当您在 Android Studio 中剖析利用时,CPU Profiler 会实现下面所有的计算,您只有了解这些数字是怎么产生的即可:

比照左右两边: Flame Chart 比拟便于发现总耗时很长的调用链,而 Top Down Tree 则不便察看其中每一步所耗费的准确工夫。作为一个表格,Top Down Tree 也反对按独自维度进行排序,这点同样十分实用。

Bottom Up Tree

当您心愿不便地找到某个办法的调用栈时,Bottom Up Tree 就派上用场了。” 树 ” 如其名,Bottom Up Tree 从底部开始构建,这样咱们就能通过在节点上一直增加调用者来反向构建出树。因为每个独立节点都能够构建出一棵树,所以这里其实是森林 (Forest):

让咱们再做些计算来搞定这些工夫信息。

表格有四行,因为咱们有四个树在森林中。从节点 C 开始:

  • Self Time 是 4 + 2 = 6 秒钟;
  • C 没有调用其余办法,所以 Children Time 是 0;
  • 后面两者相加,总工夫为 6 秒钟。

看起来与 Top Bottom Tree 别无二致。接下来开展 C 节点,计算 C 的调用者 B 和 D 的状况。

在计算 B 和 D 节点的相干工夫时,状况与后面的 Top Bottom Tree 有所不同:

  • 因为咱们在构建基于 C 节点的 Bottom Up Tree,所以所有工夫信息也都是基于 C 节点的。这时咱们在计算 B 的 Self Time 时,该当计算 C 被 B 调用的工夫,而不是 B 本身执行的工夫,这里是 4 秒;对于 D 来说,则是 2 秒。
  • 因为只有 B 和 D 调用 C 的办法,它们的 Total Time 之和应与 C 的 Total Time 相等。

下一个树是 B 节点的 Bottom Up Tree,它的 Self Time 是 3 秒,Children Time 是用来调用其余办法的工夫,这里只有 C,所以是 2 秒。Total Time 永远都是前两者之和。上面便是整个表格开展的样子:

当您想要察看某个办法如何被调用,比方这个 nanoTime() 办法时,您能够应用 Bottom Up Tree 并察看 nanoTime 办法的子节点列表,通过左边的工夫数据,您能够找到那个您所感兴趣的调用:

备忘表

后面介绍了四种不同的数据图表,并且还具体解释了一些数据是如何被计算出来的。如果您感觉脉络太多很难记住,没关系,上面这个扼要的备忘表就是为您筹备的:

总结

本文介绍了 Android Studio Profiler 中的两种数据分析工具。

其中 Memory Profiler 能够自动检测 Activity 和 Fragment 的内存透露,而通过理解和应用 Memory Profiler 中数据分析性能提供的数据,也能够发现和解决其余类型的内存透露问题。

无关 CPU Profiler 则介绍了 Call Chart、Flame Chart、Top Down、Bottom Up 这四种维度的数据出现。

心愿这些内容可能帮忙您更加理解 Android Profiler。如仍有疑难,欢送在下方留言。也欢送通过 Android Studio 反馈应用中遇到的问题。

您也能够通过视频回顾 2019 Android 开发者峰会演讲 —— 读懂 Android Studio 剖析工具数据。

退出移动版