Android17应用内存限制--App:我人不舒服,系统:那你走吧

不知道各位有没有听过下面这种类似的段子

  • 90后生病:我发烧38.5度,头晕得厉害,但是工作没做完,没做完就请假太对不起老板了,我得坚持下去
  • 00后生病:劳资今天精神状态不适合上班,灵魂出窍中,请假,已读不回勿扰

而当我今天打开许久没看的Android开发者文档后,吓了一跳,谷歌又整新活儿了,Android17出了一个应用内存限制的新特性,越看越觉得Android17的手机应用里面,也出了不少"00后"

背景

总体先说下怎么回事,Android 17 引入了基于设备总RAM的应用内存限制机制。系统会"保守地设置限制",在极端内存泄漏等异常情况引发系统范围不稳定(界面卡顿、耗电过快、应用被终止)之前主动采取行动,目的是为应用和用户"打造更稳定、更确定的环境"。 个人解读:谷歌为了用户考虑,当用户使用的应用出现异常的时候,就不让用户用了,就像是app说:我有点发烧(电池过热),四肢酸痛(界面卡顿),吃坏肚子了(内存泄漏),活干不动了,系统就说:好的,你走吧,可以下班了...是这个意思吧?

影响范围

值得注意的是,这个应用内存限制的新特性是针对所有平台的,也就是不管你的应用升不升级targetSdkVersion版本,只要运行在Android17的设备上,都必须考虑这件事,但是人家也标注了,不是所有设备都会存在这个新特性

那究竟部分设备是指的哪些设备,并没有明说,不过按照以往所有新特性的规律,不排除将来对所有设备都开放的可能性

行为表现

所以对于开发者来讲,目前能做的只能是知道应用是不是因内存达到上限而被强制退出的,以及如何预防这件事情的发生,当应用突破内存限制时,系统会终止该应用进程,但是不会crash,也不会抛出OOM,仅仅只会有一个退出原因记录REASON_OTHER,然后说明中包含字符串 MemoryLimiter:AnonSwap,所以如果我们不做任何事情的话,线上如果有用户说:我的应用无故退出了,你大概率会去犟嘴:胡说,我啥日志都没看到

问题捕获

既然不会crash,那么肯定try-catch的方式也不能用,只能通过上报日志的方式知道了,前面说到了,应用被强制退出会有个原因记录,我们可以上报这个记录,这个记录是通过ApplicationExitInfo来获取的,代码如下

建议在 Application.onCreate()首页 Activity 中注册此检查,并上报到日志/监控系统。

使用基于触发器的生产环境分析

Android 平台提供了高级可观测性 API,支持在生产环境中基于触发器自动捕获数据:

触发器 触发时机 用途
TRIGGER_TYPE_ANOMALY 系统检测到异常行为(如内存用量过量)时触发,在系统采取措施之前 捕获内存达到限制前的堆转储
TRIGGER_TYPE_OOM 应用抛出 OutOfMemoryError 后,下次启动时触发 分析 OOM 现场

结合 Android Vitals 监控 LMK 事件

通过 Android Vitals(Google Play Console)跟踪低内存终止 (LMK) 事件:

问题分析

当确认应用被内存限制器终止后,需要分析具体原因。

本地分析:Android Studio Memory Profiler

Memory Profiler 可以分析:

  • 内存用量的实时图表和趋势
  • 分配的 Java/Kotlin 对象数量
  • GC 事件发生的时间与频率
  • Java 堆的快照(Heap Dump),检查大对象与泄漏
  • 所有分配对象的堆栈轨迹

命令行分析:dumpsys meminfo

bash 复制代码
# 查看某个进程的内存详情
adb shell dumpsys meminfo <package_name>

# 示例输出关键字段说明
# Native Heap     - 原生代码分配的内存
# Dalvik Heap     - Java/Kotlin 堆
# .so mmap        - 共享库映射
# .jar .apk       - 代码资源映射
# Graphics        - 图形缓冲区
# Stack           - 线程栈
# Cursor          - 数据库游标
# Ashmem          - 匿名共享内存

重点关注 PSS(Proportional Set Size)------按比例分摊共享库后的实际物理内存,这是与系统限制最相关的指标。

生产环境分析:ProfilingManager

生产环境中,通过 ProfilingManager 的基于触发器的分析能力:

  • TRIGGER_TYPE_ANOMALY:系统检测到内存异常(达到限制前触发器)时自动转储堆
  • TRIGGER_TYPE_OOM:OOM 发生后下次启动时触发

查询系统可用内存

应该如何适配

知道了问题,那么接下来就要做的是我们如何去适配这个新特性,才能让应用在内存限制内运行

建立内存基线

针对不同的设备配置(RAM 大小),建立应用的内存使用基线:

  1. 收集各场景峰值内存:启动、主页、列表滑动、详情页、图片浏览、后台切换
  2. 按 RAM 分档:4GB、6GB、8GB、12GB+ 设备分别记录
  3. 设置报警阈值:设定为系统限制的 80%,接近时触发告警

优化图片加载

图片是内存占用的最大来源之一:

实现 onTrimMemory 及时释放资源

使用经过优化的数据容器

避免 Java 标准库中带有自动装箱开销的容器:

推荐使用 替代 节省
SparseArray HashMap<Integer, Object> 每条目减少 1-2 个对象
SparseBooleanArray HashMap<Integer, Boolean> 同上
LongSparseArray HashMap<Long, Object> 同上
原始数组 ArrayList<Integer> 无装箱开销

精简代码与依赖

通过启用 R8 缩减应用总大小

  • 应避免的全局规则:

    • -dontoptimize:完全停用整个应用的优化,导致可执行文件更大、速度更慢。
    • -dontshrink:防止移除未使用的代码和资源。
    • -dontobfuscate:防止名称缩减,从而错失宝贵的内存节省机会(尤其是在大型应用中)。
  • 避免使用软件包级通配符:-keep class com.example.package.** { *; } 等宽泛的规则会强制 R8 保留相应软件包中的每个类、字段和方法。这会完全阻止 R8 移除、优化或缩小相应软件包中的代码

  • 使用默认 R8 配置文件:始终使用 proguard-android-optimize.txt

  • 精简 Protobuf:始终使用 protobuf-lite(精简版)而非完整版

谨慎管理 Service

启动 Service 后,系统会倾向于保持其进程存活,这将减少 LRU 缓存中的可用进程数,影响应用切换效率:

避免内存抖动

内存抖动指短时间内大量分配临时对象,导致频繁 GC,消耗电量和增加帧绘制时间:

测试与调试工具

adb memory-limiter 命令

Android 17 提供了一组新的 adb 调试工具,用于模拟和调试内存限制:

bash 复制代码
# 查看当前内存限制状态
adb shell am memory-limiter status

# 对指定 UID 忽略限制(用于白名单调试)
adb shell am memory-limiter ignore <uid>

# 忽略所有进程的限制
adb shell am memory-limiter ignore all

# 取消所有忽略
adb shell am memory-limiter ignore none

# 对指定 PID 设置手动限制(如 30MB)
adb shell am memory-limiter manual <pid> 30

# 移除手动限制
adb shell am memory-limiter manual <pid> max

# 恢复系统默认限制
adb shell am memory-limiter manual <pid> none

模拟低内存场景

bash 复制代码
# 模拟低内存触发 onTrimMemory
adb shell am send-trim-memory <package> <level>
# level: MODERATE, BACKGROUND, COMPLETE, UI_HIDDEN

# 压力测试 - 持续分配内存直到被限制
# 建议结合 instrumentation 测试使用

持续监控脚本

bash 复制代码
#!/bin/bash
# monitor_memory.sh - 监控应用内存使用变化

PACKAGE="com.example.app"

while true; do
    TIMESTAMP=$(date +"%T")
    PSS=$(adb shell dumpsys meminfo $PACKAGE | grep "TOTAL PSS" | awk '{print $3}')
    echo "[$TIMESTAMP] PSS: ${PSS}kB"
    sleep 5
done

总结

其实说白了也没啥大不了的,做的还是平时我们做的一些性能优化的事情,对于大部分Android老法师来讲,优化个内存每个人都有自己的手段,就算谷歌不弄出这个新特性,谁家kpi里面没几个性能优化的指标呢?所以,比起前面几个版本的某些特性,这个咱还真不用放心上

相关推荐
问心无愧05132 小时前
ctf show web入门101
android·前端·笔记
一池秋_2 小时前
chroot-debian一键部署
android·容器·debian
超梦dasgg2 小时前
APP 壳、加固、脱壳 完整通俗讲解(安卓为主,兼顾 iOS)
android·ios
猪脚饭还是好吃的2 小时前
【分享】C4droid 安卓C++编译器 手机编程超便捷
android·c++·智能手机
AI浩2 小时前
【数据处理】基于 SAM3 的 LabelMe 标注统一校正方法
android·开发语言·kotlin
恋猫de小郭2 小时前
真正的跨平台 AI 自动化框架,甚至还支持鸿蒙
android·前端·flutter
私人珍藏库2 小时前
【Android】 VidFetch一键下载各大平台视-内置播放器
android·app·工具·软件·多功能
2501_932750262 小时前
Android Activity 生命周期解析
android
zfoo-framework2 小时前
[kotlin项目中使用luban配置] 1.java + kotlin共存
kotlin