Android 高内存压力:如何诊断和修复错误

内存是您的 Android 应用程序拥有的最重要的资产之一。Android 平台尝试将尽可能多的应用程序保留在内存中,即使它们不使用时也是如此。这不仅仅是组成应用程序的文件的缓存,而是正在运行的应用程序进程及其线程。这种行为使应用程序和任务之间的切换变得快速,并使最终用户感觉设备“活泼”。然而,在低端设备上,如果正在运行的应用程序占用的内存超过其公平份额,事情就会开始变得混乱。这种情况的结果是增加了所谓的“记忆压力”。

您可以将内存压力视为主要应用程序,即用户与之交互的应用程序,它将其他应用程序挤出内存。这是一个过程,不会同时发生,也不会一直发生。取而代之的是,Android 平台(特别是 Low Memory Killer 或 LMK)将采取增量步骤,试图为需要大量内存的前台应用程序释放更多 RAM。

在其他平台上看不到的程度,Android 主要由相互依赖的应用程序生态系统组成,使用共享内存或进程间通信 (IPC) 相互通信。您使用Context.getSystemService检索的许多服务类 实际上是轻量级外观,它们使用 IPC 与系统服务进程进行通信。这造就了一个惊人的互联系统,应用程序可以安全地顺畅地共享数据和资源,并且对于最终用户而言,整体体验变得“超过其各个部分的总和”。它还可能导致无法预料且难以调试的稳定性问题。

内存压力如何影响应用程序稳定性

那么内存压力是如何影响你的应用程序稳定性的呢?最常见和最明显的答案是内存不足错误,但在 Android 上还有其他几种可能的情况。如果您的应用程序在前台,那么其他应用程序将被终止,如果您的应用程序在后台,用户不会注意到它是否被杀死,对吧?错误的。

您的应用程序可能会被终止,因为其他应用程序消耗了太多内存,并且如果您的应用程序当时正在执行任何工作(备份、服务器同步、缓存修剪等),您最终可能会收到一个不支持的崩溃报告似乎与内存有关。

另一种可能导致问题的内存情况是当用户从一个应用程序导航到另一个应用程序时您的应用程序被终止。例如,在与其他应用程序共享照片或导航到 Chrome 中托管的帮助页面时。如果没有足够的内存将两个应用程序同时保存在内存中,Android 将在后台终止应用程序并在用户导航返回时将其恢复。起初这似乎不是问题,但您的应用程序可能必须冷启动,从而导致严重延迟并可能导致应用程序无响应 (ANR) 报告,因为系统会重新启动您的应用程序并卸载前一个应用程序。这在内容共享等用例中可能会变得更糟。例如,通过消息应用程序将您惊人的照片编辑应用程序中的照片发送给朋友。

Bugsnag 中的端到端内存报告

最近更新了有关 Android 的 Bugsnag 报告。从版本 5.12.0 开始 ,我们添加了一些新参数,我们会自动向您的仪表板报告这些参数。

Bugsnag 将内存报告分为两个现有的元数据类别:App 和 Device。应用程序内存属性特定于您的  应用程序,而 设备属性 可让您了解设备上同时发生的其他情况。我们将这些字段分为两个主要类别(与我们捕获的许多其他字段一样):应用程序(特定于您的应用程序)和设备(特定于生成报告时运行您的应用程序的设备)。

在 Bugsnag 仪表板的 App 选项卡下,我们报告:

  • totalMemory您的应用程序当前可用的内存总量,直接从Runtime.totalMemory报告。此值的确切定义因设备而异,但其意义保持不变:这是您的 Java / Kotlin 对象根据平台占用的空间量。这通常包括一些未使用的(空闲)内存,可用于分配新对象而无需扩大堆。
  • freeMemory
    Java / Kotlin 对象当前未消耗的可用内存量,直接从Runtime.freeMemory报告。这是在垃圾收集器需要运行之前新对象可以消耗多少空间,或者将分配更多堆空间。
  • memoryUsage
    报告为 的便利值totalMemory - freeMemory。这是生成报告时您的应用程序使用的内存量的估计值。
  • memoryLimit
    Android 允许您的应用用于 Java / Kotlin 对象的最大内存量,直接从Runtime.maxMemory报告。此处报告的值会因设备配置和确切的 Android 版本而有很大差异。一些设备会报告接近已安装 RAM 数量的值,而其他设备会报告小至 8mb 的值。
  • lowMemory
    在生成报告之前,平台是否向您的应用报告了内存不足的情况。此值源自更详细的memoryTrimLevel,并且主要用于向后兼容。
  • memoryTrimLevel
    向您的应用报告的最新修剪级别。下面将更详细地讨论,此字段可指示系统内存压力以及生成报告时应用程序的优先级。

在我们报告的设备选项卡下:

  • totalMemory
    正如包装盒上所说:设备可用的内存总量。这取决于设备配置和 Android 版本,但最常见的是物理安装的 RAM 量。
  • freeMemory
    生成报告时 Android 认为“空闲”的内存量。这通常很低,因为 Android 会在内存中维护大量缓存数据,这不算“免费”。

内存调整级别

一项重大变化是,我们现在  在应用程序选项卡中跟踪 JVM 和 NDK 报告的内存修剪级别。这使您可以查看上次向您的应用报告的内存压力类型:

此属性是使用onTrimMemory报告给您的应用程序的最新值 ,提供有关位图分配失败或应用程序终止原因的宝贵见解。我们还开始在传递这些事件时自动收集 面包屑 ,因此您将了解导致崩溃报告的内存压力。

“设备”选项卡还包括对物理设备内存情况的清晰了解,包括已安装 RAM 的数量 (totalMemory) 以及该内存中有多少被认为是空闲和可用的 (freeMemory)。当用户设法使应用程序中的内存密集型功能崩溃时,了解设备上有多少可用 RAM 可以带来有价值的见解。

并非所有错误都值得修复。只修复那些重要的。

虽然内存在旗舰和中端设备上通常不是问题,但 Android 生态系统中的许多商品设备在高内存压力情况下可能会导致奇怪和意外的稳定性问题。了解您的应用程序的哪些功能正在被访问;导致崩溃的内存压力;设备的整体内存健康状况可以帮助您找到这些错误的真正来源。知道错误何时是由您自己的应用程序(或其他应用程序)的内存压力引起的,可以更轻松地确定哪些值得修复,哪些可以安全地保留。

android-high-memory-pressure-how-to-diagnose-and-fix-the-errors