一、简介
Memory Profiler 是 Android Profiler 中的一个组件,可帮助您识别导致应用卡顿、冻结甚至崩溃的内存泄漏和流失。 它显示一个应用内存使用量的实时图表,让您可以捕获堆转储、强制执行垃圾回收以及跟踪内存分配。
二、为什么应分析您的应用内存
Android 提供一个托管内存环境—当它确定您的应用不再使用某些对象时,垃圾回收器会将未使用的内存释放回堆中。 虽然 Android 查找未使用内存的方式在不断改进,但对于所有 Android 版本,系统都必须在某个时间点短暂地暂停您的代码。 大多数情况下,这些暂停难以察觉。 不过,如果您的应用分配内存的速度比系统回收内存的速度快,则当收集器释放足够的内存以满足您的分配需要时,您的应用可能会延迟。 此延迟可能会导致您的应用跳帧,并使系统明显变慢。
尽管您的应用不会表现出变慢,但如果存在内存泄漏,则即使应用在后台运行也会保留该内存。 此行为会强制执行不必要的垃圾回收 Event,因而拖慢系统的内存性能。 最后,系统被迫终止您的应用进程以回收内存。 然后,当用户返回您的应用时,它必须完全重启。
为帮助防止这些问题,您应使用 Memory Profiler 执行以下操作:
三、Memory Profiler 概览
要打开 Memory Profiler,可以以下步骤操作:
即使您的应用中不使用 C++,您也可能会看到此处使用的一些原生内存,如处理图像资源和其他图形时,即使您编写的代码采用 Java 或 Kotlin 语言,Android 框架也会使用原生内存处理各种任务。
四、查看内存分配
内存分配显示内存中每个对象是如何分配的。 具体而言,Memory Profiler 可为您显示有关对象分配的以下信息:
如果您的设备运行 Android 8.0 或更高版本,您可以随时按照下述方法查看您的对象分配: 只需点击并按住时间线,并拖动选择您想要查看分配的区域(如下图所示)。 不需要开始记录会话,因为 Android 8.0 及更高版本附带设备内置分析工具,可持续跟踪您的应用分配。
在 Call Stack 标签中,点击任意行以在编辑器中跳转到该代码。
五、捕获堆转储
堆转储显示在您捕获堆转储时您的应用中哪些对象正在使用内存。 特别是在长时间的用户会话后,堆转储会显示您认为不应再位于内存中却仍在内存中的对象,从而帮助识别内存泄漏。 在捕获堆转储后,您可以查看以下信息:
对象所分配到的调用堆栈。 (目前,如果您在记录分配时捕获堆转储,则只有在 Android 7.1 及更低版本中,堆转储才能使用调用堆栈。)
要捕获堆转储,在 Memory Profiler 工具栏中点击 Dump Java heap 。 在转储堆期间,Java 内存量可能会暂时增加。 这很正常,因为堆转储与您的应用发生在同一进程中,并需要一些内存来收集数据。
堆转储显示在内存时间线下,显示堆中的所有类类型,如上图所示。
如果您需要更精确地了解转储的创建时间,可以通过调用 dumpHprofData() 在应用代码的关键点创建堆转储。
要检查您的堆,请按以下步骤操作:
或者,点击实例名称旁的箭头以查看其所有字段,然后点击一个字段名称查看其所有引用。 如果您要查看某个字段的实例详情,右键点击该字段并选择 Go to Instance 。
默认情况下,堆转储 不会 向您显示每个已分配对象的堆叠追踪。 要获取堆叠追踪,在点击 Dump Java heap 之前,您必须先开始 记录内存分配 。 然后,您可以在 Instance View 中选择一个实例,并查看 Call Stack 标签以及 References 标签,如图 5 所示。不过,在您开始记录分配之前,可能已分配一些对象,因此,调用堆栈不能用于这些对象。 包含调用堆栈的实例在图标
上用一个“堆栈”标志表示。 (遗憾的是,由于堆叠追踪需要您执行分配记录,因此,您目前无法在 Android 8.0 上查看堆转储的堆叠追踪。)
在您的堆转储中,请注意由下列任意情况引起的内存泄漏:
Activity
、
Context
、
View
、
Drawable
和其他对象,可能会保持对
Activity
或
Context
容器的引用。
Activity
实例的非静态内部类,如
Runnable
。
在类列表顶部,您可以使用左侧下拉列表在以下堆转储之间进行切换:
默认情况下,此堆中的对象列表按类名称排列。 您可以使用其他下拉列表在以下排列方式之间进行切换:
默认情况下,此列表按 Retained Size 列排序。 您可以点击任意列标题以更改列表的排序方式。
在 Instance View 中,每个实例都包含以下信息: