2026 年 8 月,Google 在 Android Developers Blog 连发两篇与应用内存直接相关的文章:一篇讲 Android 17 向全 RAM 档位扩展 per-app memory limits,另一篇宣布 Google Play 新的质量门槛,覆盖内存占用、DEX 优化和换机 Zero-Tap Sign-In。细则在 Play Console 技术质量要求文档里(公告日 2026-08-26)。
如果你只跟了其中一篇,很容易误判自己有没有风险。
Memory Limiter 是设备上当场发生的事。用户可能只觉得「卡了一下回到桌面」,Vitals 曲线也未必立刻掉头------因为那是单次会话的尖峰。Play 门槛是另一套算法:28 天、90 分位、按 RAM 档和进程状态分桶。开发机测不出,单机峰值也代表不了。两件事叠在一起,才是完整图景:系统层 cgroup 限流,商店层 P90 卡 bad behavior。
Google 把背景归到内存硬件供应约束,新机 RAM 不再一味往上堆。这话可信不可信另说,但用户评判标准确实没变。卡顿、闪退、换机要重新登录,照样会打低分、卸载。做 App 的人得先分清三件事:谁在杀进程、谁在降可见度、自己手头该先量哪几个数。

第 1 章 双轨治理:系统 Memory Limiter 与 Play bad behavior
| 维度 | Android 17 Memory Limiter | Google Play 质量门槛 |
|---|---|---|
| 生效逻辑 | 单应用超 cgroup 预算 → zRAM 换页 → 可能杀进程 | 28 天 P90 超阈值 → bad behavior |
| 主要信号 | ApplicationExitInfo:REASON_OTHER + MemoryLimiter:AnonSwap |
Android vitals:Anonymous RSS + Swap、Bitmap、DEX 优化占比 |
| 首批节奏 | Pixel 起,向 4GB~16GB+ 扩展 | 2027-02 内存/DEX;2027-04 Zero-Tap Sign-In |
| 未达标后果 | 卡顿、无栈终止 | 可见度与发布能力可能下调 |
系统侧保整机响应,商店侧用人口级采样逼长期优化。Limiter 管单次会话里的 outlier,Vitals 抓持续高占用的应用组合,两边不重复------但用户体感上可能分不清是哪一种在起作用。
走一遍真实链路
假设某信息流 App 在 4 GB 机上后台留了 250 MB Bitmap,同时 Anonymous RSS 顶到 1.2 GB:
- 系统侧 :若当次会话 cgroup 预算被突破,先 zRAM 换页,用户刷列表时感到掉帧;再涨则进程被 terminate,
ApplicationExitInfo里出现MemoryLimiter:AnonSwap,Crashlytics 可能无记录。 - 商店侧:28 天窗口里,4 GB 档 Background 的 Anonymous RSS P90 上限是 1 GB,Bitmap P90 上限是 200 MB------两条线都可能记 bad behavior,且彼此独立。
同一份内存问题,可能在一天内让用户觉得「卡」,在一个月内让 Console 飘黄。只修其中一个维度,另一个照样找上门。
跟 LMK 别混
LMK / lmkd |
Memory Limiter | Play Vitals | |
|---|---|---|---|
| 触发条件 | 系统整体内存压力 | 单应用超 cgroup 匿名内存预算 | 28 天 P90 超阈值 |
| 选择对象 | 按 adj 等挑 victim | 约束 UID ≥ 10000 的应用,无白名单 | 按 App/Game、RAM 档、进程状态分桶 |
| 典型信号 | 低 adj 进程先死 | MemoryLimiter:AnonSwap |
Console bad behavior 标记 |
| 开发者误区 | 「又是杀后台」 | 当成 OOM 查 | 用开发机峰值自证合格 |
对外沟通时别随口说成「又是 LMK 杀后台」。机制讲错了,排障方向也会偏。
关于 bad behavior 之后「可见度下调」具体怎么执行,官方目前给的是方向性描述,细到每个品类降多少、持续多久,还得靠后续案例和 Console 里的实际反馈来校准。排期时别假设「离阈值还有一点余量就安全」------P90 看的是尾部用户,尾部往往集中在低端机和长会话场景。
第 2 章 Memory Limiter 如何工作:先换页,再终止
官方描述超额占用是渐进的,分两步:
- zRAM Swapping :进程碰到
memory.high,内核对对应 cgroup 做定向回收,匿名页压进 zRAM。进程不一定马上死,但压缩/解压吃 CPU,用户侧常见 UI jank。 - 进程终止:zRAM 之后内存还在涨,系统 terminate 进程。
很多团队的第一反应是查 OOM 或 Java crash,这里往往对不上。字段口径跟 Play 的 Anonymous RSS + Swap 一个方向:看应用私有数据(Java/Kotlin 堆、native 分配、匿名映射),不是盯 Java 堆 MAX 就够。图片库、WebView、native 泄漏,都可能在堆指标「正常」时把匿名内存顶上去。
现场怎么认
读 ApplicationExitInfo.getDescription(),出现 MemoryLimiter:AnonSwap 就是 Memory Limiter 介入。启动时扫一遍历史记录,成本很低,收益很高:
kotlin
val exits = activityManager.getHistoricalProcessExitReasons(packageName, 0, 20)
exits.filter {
it.reason == ApplicationExitInfo.REASON_OTHER &&
it.description?.contains("MemoryLimiter:AnonSwap") == true
}.forEach { exit ->
// 上报:timestamp、rss、进程状态、前后台切换上下文
logLimiterExit(exit)
}
这类终止往往没有传统 crash 栈,Crashlytics 里也可能干干净净。用户反馈「用着用着突然回桌面」,客服工单却找不到对应崩溃------多半就是这类信号没接上。
本地压测
ADB am memory-limiter 可以在 Android 17 设备上手动逼近上限(status 看当前策略,manual 对指定 PID 设 cap)。压测能复现「先卡后死」,比等线上用户碰运气靠谱。
另一点容易忽略:Android 17 起应用还没有运行时 API 能查平台分配的 memory limit。你只能估、只能压,没法在代码里读到一个硬数字。正常业务一般有裕量;泄漏型 outlier 照样会撞线,而且撞之前用户已经先感到卡了。
第 3 章 Play 2027 门槛:三条指标与分桶规则
Play 的三条线彼此独立:动态内存(Anonymous RSS + Swap)、Bitmap、DEX 优化。任意一条在对应分桶里超 P90,都可能记 bad behavior。2027 年 2 月 1 日起强制执行内存和 DEX 相关项;换机登录单独卡在 2027 年 4 月。
3.1 动态内存:Anonymous RSS + Swap
从加载到运行,贯穿前台、User-perceived services、后台、缓存各状态的私有内存都算(swap 含 zRAM 压缩页)。评估用 90 分位(28 天滚动窗口),按 App / Game、设备 RAM 档位分桶,仅手机/平板。
P90 到底意味着什么? 不是「平均值还行」,而是:28 天内,该分桶里 10% 的最差会话仍然达标。用户群里只要有 10% 的 4 GB 机长时间后台挂着,你的 Background P90 就会被这部分人拉高。开发机跑一夜没事,说明不了什么。
进程状态怎么理解:
| 状态 | 大致含义 | 考核特点 |
|---|---|---|
| Foreground | 用户正在交互的界面 | 阈值最高,长会话页最容易顶 |
| User-perceived | 前台服务、导航、通话等用户可感知后台 | 介于前台与纯后台之间 |
| Background | 不可见但仍运行 | 阈值紧,泄漏型问题先在这里暴露 |
| Cached | 进程在缓存列表 | 动态内存阈值不单独考核;Bitmap 仍看 400 MB 线 |
App 分桶(Cached 状态不单独考这条动态内存阈值;0~4 GB、16 GB+ 档暂无考核线):
| RAM 档位(Total Memory) | Foreground P90 | User-perceived | Background |
|---|---|---|---|
| 4 GB(3200~4800 MB) | ≤ 2 GB | ≤ 1 GB | ≤ 1 GB |
| 6 GB(4800~6800 MB) | ≤ 2.25 GB | ≤ 1.25 GB | ≤ 1.25 GB |
| 8 GB(6800~9216 MB) | ≤ 2.25 GB | ≤ 1.5 GB | ≤ 1.5 GB |
| 12 GB(9216~14336 MB) | ≤ 3.25 GB | ≤ 1.75 GB | ≤ 1.75 GB |
| 16 GB(14336~18432 MB) | ≤ 4.25 GB | ≤ 2 GB | ≤ 2 GB |
Game 分桶(同上,Cached 不考动态内存;档位划分与 App 一致):
| RAM 档位(Total Memory) | Foreground P90 | User-perceived | Background |
|---|---|---|---|
| 4 GB(3200~4800 MB) | ≤ 2.25 GB | ≤ 2 GB | ≤ 2 GB |
| 6 GB(4800~6800 MB) | ≤ 2.75 GB | ≤ 2.5 GB | ≤ 2.5 GB |
| 8 GB(6800~9216 MB) | ≤ 3.5 GB | ≤ 2.75 GB | ≤ 2.75 GB |
| 12 GB(9216~14336 MB) | ≤ 4 GB | ≤ 3.2 GB | ≤ 3.2 GB |
| 16 GB(14336~18432 MB) | ≤ 5 GB | ≤ 3.5 GB | ≤ 3.5 GB |
官方按 Play Console 里配置的 App / Game 品类分表,依据是游戏前台长会话、native 引擎占内存的模式与工具类 App 不同。别把品类改成与核心功能不符的类别来蹭 Game 阈值------这违反商店 Metadata 政策。
App 与 Game 前台阈值差距不大,User-perceived / Background 差距才明显。以 8 GB 档为例,Background 上限 App 是 1.5 GB,Game 是 2.75 GB,几乎翻倍:
| RAM 档位 | App Background | Game Background | 差额 |
|---|---|---|---|
| 4 GB | 1 GB | 2 GB | +1 GB |
| 6 GB | 1.25 GB | 2.5 GB | +1.25 GB |
| 8 GB | 1.5 GB | 2.75 GB | +1.25 GB |
| 12 GB | 1.75 GB | 3.2 GB | +1.45 GB |
| 16 GB | 2 GB | 3.5 GB | +1.5 GB |
另一点容易忽略:分档用的是设备 Total Memory(系统上报的总内存),可以低于包装盒上的 Physical RAM 标称值。同一款「8 GB 手机」,分桶边界是 6800~9216 MB,别按营销规格自行归类。
别直接套用 App 的数去估游戏包,尤其 hybrid 应用(游戏壳 + 重型社交/商城模块)要按 Console 实际品类看表。
3.2 Bitmap 内存:非前台别长期囤图
Bitmap 只有 UI 可见时才有渲染意义。Vitals 对 User-perceived / Background 的 Bitmap P90 > 200 MB 、Cached > 400 MB 记 bad behavior------App 与 Game 共用同一套 Bitmap 阈值 ,没有 Game 豁免线。阈值不是零,是给 onTrimMemory 留缓冲;卡的是后台长期持有大图,不是短暂过渡状态。
粗算一下就知道 200 MB 有多紧:一张 1080p、ARGB_8888 的全屏图大约 8 MB。后台攥 25 张没释放,就已经踩线。信息流如果按「一屏 10 条、每条 2 张缩略图」缓存,两轮下来就是 160 MB------还没算解码过程中的临时 buffer。
信息流、相册预览、电商详情页这类 App 要特别当心:前台切后台后,列表里的缩略图如果还攥在手里,P90 很容易超。onTrimMemory 写了但图片库没接回调,等于没写。Glide / Coil / Fresco 的 memory cache 策略,建议按 RAM 档分级,别所有机型同一套上限。
3.3 DEX 优化:至少 25%
2027 年 2 月起,非 negligible DEX 要求 shrinking、optimization、obfuscation 各 ≥ 25%:
| 类型 | 触发条件 | 三项各自要求 |
|---|---|---|
| App | 未压缩 DEX > 10 MB | shrink / optimize / obfuscate 各减 ≥ 25% |
| Game | 未压缩 DEX > 50 MB | 同上 |
R8 或其他 shrinker 都行;App Bundle Explorer 会展示各次上传的优化占比。官方建议 proguard-android-optimize.txt,别在 gradle.properties 里长期关 R8 full mode。
举个数量感:某 App 上传 20 MB 原始 DEX,三项各需至少减掉 5 MB(25%)。如果 shrinking 只少了 3 MB,即使 optimize 和 obfuscate 都达标,照样不过。老项目最怕这条------多年没动 ProGuard 规则,一开 R8 先炸反射调用,再炸第三方 SDK。「开 R8」和「能过 25% 且不上线回归」之间,往往还差一轮规则修补和灰度。
第 4 章 工具链:从 Vitals 到 ProfilingManager
2026 年下半年起,Play Console 配套能力陆续上线:
| 层级 | 工具 | 用途 |
|---|---|---|
| 宏观 | Android vitals → Memory | RSS+Swap、Bitmap 按 RAM 档与进程状态下钻 |
| 终止事件 | Crashlytics 20.1.0+、ApplicationExitInfo |
OOM 与 Memory Limiter 退出上下文 |
| 产线剖面 | ProfilingManager(API 35+) |
TRIGGER_TYPE_OOM、TRIGGER_TYPE_ANOMALY 触发 heap dump |
| 预警 | Vitals 概览页 | 超 bad behavior 阈值时主动告警 |
| 后续 | 2026 年下半年 | 各状态停留时长、Memory Limiter 更深诊断(官方预告) |
TRIGGER_TYPE_ANOMALY 值得接,但别高估落地速度:要 API 35+,还要处理 dump 上传、存储和隐私合规。它的价值在于系统判定异常(含逼近 memory limit)时,能在强制杀进程前回调------正好补上「无栈终止」的产线盲区。
第一周就能做的三件事
不用一上来就全栈,按这个顺序推进就够起步:
- Console 基线(半天):打开 Vitals → Memory,按 4 / 6 / 8 GB 档分别看 Foreground、Background 的 RSS+Swap 和 Bitmap 曲线,记下离阈值最近的一档。
- 启动扫退出原因(1~2 天) :主进程启动时读
ApplicationExitInfo,把MemoryLimiter:AnonSwap和 OOM 分开上报;先接日志,再接告警。 - ADB 压测(1 天) :在 Android 17 测试机用
am memory-limiter复现 zRAM 阶段的 jank,确认性能团队能在本地看到掉帧,而不是等线上猜。
已有性能观测框架的团队,把 Memory Limiter 信号和 anomaly 触发放进同一 dashboard。还在只靠 Java heap 指标的,建议先把 Vitals Memory 页按 RAM 档拆开看一遍------很多时候问题出在 4 GB 档的 Background 分桶,而不是你手里那台 12 GB 开发机。
第 5 章 换机登录:Zero-Tap Sign-In 与 Restore Credentials
这条跟内存无关,但 deadline 挨得近,最好跟内存排进同一张表:
| 时间节点 | 要求 |
|---|---|
| 2026-09-30 前 | 可用 Block Store 恢复登录态,视为过渡期合规 |
| 2027-02-01 起 | 内存 / DEX 相关 bad behavior 强制执行 |
| 2027-04-01 起 | 支持登录的 App 须在 D2D / 云恢复后自动恢复登录态 |
细则:
- 标准实现是 Android Restore Credentials API(Credential Manager,Android 9+)。
- Game 暂豁免正式要求;单账号游戏仍鼓励接入。
- 金融、医疗等可申请豁免;企业专用设备不在范围。
换机手动登录伤转化,这点不用 Google 说大家也知道。真正麻烦的是存量登录体系:自建 token、多端踢登、风控二次验证,迁到 Restore Credentials 不是改一个 API 就完事。
已有 Credential Manager / passkey 集成的团队,改动量通常在一两个迭代内(Uber 公开案例也在这个量级)。还在用 WebView 登录或老版 AccountManager 封装的,得单独估人天------而且这条线跟内存优化抢的是同一拨 Android 工程师,别假装可以串行排。
第 6 章 生态影响:谁要先动、谁可以缓一缓
优先排期的,通常是这几类:
- 信息流、相册、短视频:后台 Bitmap 和 Anonymous RSS 最容易顶线;4 GB 用户占比每多 5 个百分点,Background P90 的压力就明显上一档。
- 长会话游戏、直播类:Game 动态内存阈值虽高(8 GB 档前台 3.5 GB、Background 2.75 GB),但 native 堆、纹理、音视频 buffer 叠加后峰值照样可观;Bitmap 仍卡 200 MB / 400 MB,与 App 相同;DEX 触发线 50 MB 也比 App 的 10 MB 严得多。
- DEX 体积大、多年没开 R8 的包:10 MB / 50 MB 是硬触发线,不是建议值。
- 有登录、没做换机恢复的社交、工具、金融 App:2027-04 是硬线,而且跟内存无关,最容易被排期表漏掉。
相对省事的,多半是已经用 Vitals 管过 ANR/崩溃、R8 在跑、onTrimMemory 有实际释放逻辑的中型 App。补监测、补压测、对照 Console 分桶看一圈,通常一两周内能摸清差距在哪。无登录 App,或纯 Game(只看 Zero-Tap 这一条),短期内压力确实小一些。
OEM / 渠道侧,Memory Limiter 往多厂商、多 RAM 档扩,「高端机无限堆内存」的产品假设在系统层站不住;Play 阈值是同一方向的另一刀。媒体有时把移动内存收紧和数据中心 DRAM 争用放在一起聊,那是宏观叙事;你排期时还是以 Console 里的分桶数据和自家 Vitals 曲线为准,别被二手解读带着走。
结论与建议
2026 下半年起,应用内存从「最佳实践」变成硬约束:系统 enforcement 管会话级 outlier,商店 enforcement 管 28 天人口级坏行为,换机登录是并行的第三条合规线。三条线互不替代,漏任何一条都会在另一个维度挨打。
| 时间 | 动作 |
|---|---|
| 现在~2026 Q4 | Vitals Memory 基线;启动读 ApplicationExitInfo;adb memory-limiter 压测 |
| 2027-02 前 | Anonymous RSS+Swap / Bitmap P90 达标;DEX 三指标各 ≥ 25% |
| 2027-04 前 | Restore Credentials 或 Block Store(过渡期)换机登录 |
| 持续 | onTrimMemory、图片库 cache 按设备分级、Profiler + TRIGGER_TYPE_ANOMALY |
最后留三个排障时真用得上的判断:
Memory Limiter 杀进程不一定有 crash 栈,得接 MemoryLimiter:AnonSwap。Play 看 P90 分桶,开发机过关不算数,先看 4 GB 档 Background。内存和换机登录两条 deadline 别分开排------见过太多团队 Q1 赶完内存,Q2 才发现登录恢复没排上人,发布窗口直接卡死。
如果你现在只能做一件事:打开 Vitals Memory,找到离阈值最近的那个 RAM 档和进程状态组合,那就是你接下来两个月最该砸时间的点。
相关推荐
Play Console 技术质量要求(Google Help,2026-08-26) --- 内存 P90 阈值、DEX 优化占比、Zero-Tap Sign-In 等完整细则与合规日历。