记录 Java/Kotlin 内存分配有助于您识别可能导致性能问题的不可取的内存模式。分析器可以向您显示有关对象分配的以下信息:
- 分配了哪些类型的对象以及它们使用了多少空间。
- 每个分配的堆栈跟踪,包括在哪个线程中。
- 对象何时被释放。
您应该在正常和极端用户交互期间记录内存分配,以准确识别您的代码是在短时间内分配了太多对象,还是分配了会泄漏的对象。 了解更多关于为什么应该分析应用内存的信息 。
如何记录 Java/Kotlin 内存分配
要记录 Java/Kotlin 内存分配,从分析器的**主页**选项卡中选择**跟踪内存消耗(Java/Kotlin 内存分配)**任务。请注意,您需要一个可调试的应用(使用**分析器:以可调试模式运行“应用”(完整数据)**)才能记录 Java/Kotlin 内存分配。
Android Studio 默认情况下会捕获内存中的所有对象分配。如果您的应用分配了大量对象,则在分析期间,您可能会观察到应用出现明显的减速。为了在分析期间提高性能,请转到**内存分配跟踪**下拉菜单,然后选择**采样**而不是**完整**。采样时,分析器会定期收集内存中的对象分配。
要在录制过程中强制执行垃圾回收事件,请点击垃圾桶图标 。
Java/Kotlin 内存分配概述
停止记录后,您将看到以下内容
- 事件时间轴显示活动状态、用户输入事件和屏幕旋转事件。
- 内存使用时间轴显示以下信息。选择时间轴的一部分以过滤到特定时间范围。
- 堆叠图显示每种内存类别使用的内存量,左侧的 y 轴指示内存量,顶部的颜色键指示类别。
- 虚线表示已分配对象的数目,右侧的 y 轴指示数目。
- 每个垃圾回收事件的图标。
- 表格选项卡显示一个类列表。总数是在选定时间范围结束时的分配数(分配减去释放),因此首先调试总数值最高的类可能更有意义。如果您更感兴趣的是根据所选时间范围内的峰值分配来排查类问题,请按分配优先级排序。同样,剩余大小是以字节为单位的分配大小减去释放大小。
- 当您点击表格列表中的一个类时,实例面板将打开,其中包含关联对象的列表,包括它们的分配时间、释放时间以及它们的浅层大小。
可视化选项卡显示在选定时间范围内调用堆栈中所有对象的聚合视图。它基本上显示了显示的实例的调用堆栈所占用的总内存量。第一行显示线程名称。默认情况下,对象根据分配大小从左到右堆叠;使用下拉菜单更改排序方式。
使用堆下拉菜单过滤到某些堆。除了捕获堆转储时可用的过滤器之外,您还可以过滤到 JNI 堆中的类,该堆显示 Java 本地接口 (JNI) 引用在哪里分配和释放。
使用排列下拉菜单选择如何排列分配。除了捕获堆转储时可用的排列方式之外,您还可以按调用堆栈排列。
内存计数方式
您在顶部看到的数字基于您的应用已提交的所有私有内存页,根据 Android 系统。此计数不包括与系统或其他应用共享的页。内存计数中的类别如下:
- Java:来自 Java 或 Kotlin 代码分配的对象的内存。
Native:来自 C 或 C++ 代码分配的对象的内存。
即使您的应用未使用 C++,您也可能会看到此处使用了一些原生内存,因为 Android 框架使用原生内存代表您处理各种任务,例如处理图像资源和其他图形——即使您编写的代码是用 Java 或 Kotlin 编写的。
Graphics:用于图形缓冲区队列以将像素显示到屏幕上的内存,包括 GL 表面、GL 纹理等。请注意,这是与 CPU 共享的内存,而不是专用的 GPU 内存。
Stack:您的应用中原生和 Java 堆栈使用的内存。这通常与您的应用正在运行的线程数有关。
Code:您的应用用于代码和资源的内存,例如 DEX 字节码、已优化或编译的 DEX 代码、.
so
库和字体。Others:您的应用使用的系统不确定如何分类的内存。
已分配:您的应用分配的 Java/Kotlin 对象数。这并不计算在 C 或 C++ 中分配的对象。
检查分配记录
要检查分配记录,请按照以下步骤操作
- 浏览表格选项卡中的类列表,查找具有异常大的分配或总数值(取决于您要优化的内容)并且可能发生泄漏的对象。
- 在实例视图面板中,单击一个实例。根据该实例适用的内容,字段或分配调用堆栈选项卡将打开。使用字段或分配调用堆栈选项卡中的信息来确定实例是否确实需要或是不必要的重复。
右键单击任何列表条目以跳转到相关的源代码。
查看全局 JNI 引用
Java 本地接口 (JNI) 是一个框架,允许 Java 代码和原生代码互相调用。JNI 引用由原生代码手动管理,因此可能发生以下问题:
- 原生代码使用的 Java 对象保持活动时间过长。
- 如果在未首先显式删除的情况下丢弃 JNI 引用,Java 堆上的某些对象可能会变得不可访问。
- 全局 JNI 引用限制已用尽。
要解决此类问题,请在分析器中选择查看 JNI 堆以浏览所有全局 JNI 引用并按 Java 类型和原生调用堆栈对其进行过滤。右键单击字段选项卡中的实例字段,然后选择转到实例以查看相关的分配调用堆栈。
分配调用堆栈选项卡显示您的代码中 JNI 引用的分配和释放位置。
有关 JNI 的更多信息,请参阅JNI 提示。