编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • 性能优化实践

    • README
    • 公共方法论

    • 体系建设篇

    • 资源专项篇

      • CPU监控与分析
      • 内存监控与治理
      • OOM与低内存治理
      • 线程模型调度优化
      • 进程与多进程优化
        • 01.阅读说明
        • 02.贯穿案例
          • 2.1 案例背景
          • 2.2 经验派的 5 周折腾(典型反面教材)
          • 2.3 方法派的 8 天闭环
          • 2.4 上线效果
          • 2.5 案例如何串起本文
        • 03.进程物理本质
          • 3.1 一句话定义
          • 3.2 现象与代价
          • 3.3 度量准则与基准
          • 3.4 反直觉问题清单
        • 04.隔离与通信原理
          • 4.1 隔离收益 vs 通信代价
          • 4.2 典型多进程设计模式
          • 4.3 跨平台同构原理
          • 4.4 平台差异点矩阵
        • 05.度量与采集
          • 5.1 三类采集方案
          • 5.2 各方案的可见盲区
          • 5.3 跨平台采集对照表
          • 5.4 数据可信度评估
        • 06.归因决策树
          • 6.1 进程问题决策树
          • 6.2 IPC 性能归因
          • 6.3 进程拉起归因
          • 6.4 内存共享归因
        • 07.进程创建全链路
          • 7.1 Android Zygote fork 全链路
          • 7.2 iOS posix_spawn 全链路
          • 7.3 Web 新 Tab 全链路
          • 7.4 Linux fork+exec 全链路
          • 7.5 跨端进程创建对照
        • 08.IPC 通信全链路
          • 8.1 Android Binder 全链路
          • 8.2 iOS XPC 全链路
          • 8.3 Web postMessage 全链路
          • 8.4 IPC 选型决策
          • 8.5 跨端 IPC 性能对照
        • 09.共享内存全链路
          • 9.1 Android SharedMemory 全链路
          • 9.2 iOS mmap 全链路
          • 9.3 Web SharedArrayBuffer 全链路
          • 9.4 共享内存同步问题
          • 9.5 跨平台共享内存对照
        • 10.进程生命周期全链路
          • 10.1 Android 进程生命周期全链路
          • 10.2 iOS 进程生命周期全链路
          • 10.3 Web Tab 生命周期全链路
          • 10.4 ProcessExitReason 解读
          • 10.5 跨平台生命周期对照
        • 11.跨端进程对照
          • 11.1 Android 多进程模式
          • 11.2 iOS App Extension 模式
          • 11.3 Web 多进程模式
          • 11.4 跨端框架的进程模型
          • 11.5 跨端进程模式对照
        • 12.跨端对照
          • 12.1 五个全链路总览
          • 12.2 各平台优化优先级
          • 12.3 反直觉问题答疑
        • 13.治理一层数量
          • 13.1 逐进程价值评估表
          • 13.2 Push 进程合并到主进程
          • 13.3 删除守护/拉活进程
          • 13.4 评估每个 ContentProvider 是否真需独立进程
          • 13.5 进程数量收敛检查清单
        • 14.治理二层 IPC
          • 14.1 IPC 批量化
          • 14.2 主进程本地缓存 + Push 失效
          • 14.3 大数据用共享内存
          • 14.4 异步化 IPC + Future 模式
          • 14.5 IPC 治理决策表
        • 15.治理三层隔离
          • 15.1 WebView 强制进程外(必要的拆)
          • 15.2 高风险第三方 SDK 进程隔离
          • 15.3 大对象处理进程隔离
          • 15.4 ProcessExitReason 监控
          • 15.5 隔离的判断标准
        • 16.治理四层重启
          • 16.1 关键状态持久化
          • 16.2 启动期优先恢复状态
          • 16.3 合规后台任务用 WorkManager
          • 16.4 长连接业务用前台 Service
          • 16.5 ROI 排序
          • 16.6 避免反向收益
        • 17.求证实验 ⭐
          • 17.1 实验一:进程启动代价
          • 17.2 实验二:IPC 吞吐量
          • 17.3 实验三:保活策略效果
          • 17.4 实验四:CP 风暴
          • 17.5 实验五:快速重启 vs 暗保活
          • 17.6 五大实验启示
        • 18.实战案例
          • 18.1 跨端同构案例:WebView 进程隔离
          • 18.2 平台特异案例:iOS Extension 内存超限
          • 18.3 反例案例:暗保活引发的恶性循环
        • 19.防劣化体系
          • 19.1 三道防线总览
          • 19.2 编码期 Lint
          • 19.3 CI 卡口
          • 19.4 线上 SLO
          • 19.5 文化建设
        • 20.跨平台速查
          • 20.1 工具速查
          • 20.2 关键 API 速查
          • 20.3 各平台优化清单
        • 21.总结与延伸
          • 21.1 五条核心原则
          • 21.2 五个常见误区
          • 21.3 一句话总结
          • 21.4 延伸阅读
      • IO与存储性能
    • 流水线专项

    • 业务专项篇

    • 交付防御篇

  • 程序编程原理

  • 稳定性与可靠性

  • 工程化与运维

  • 方案设计思想

  • 专栏
  • 性能优化实践
  • 资源专项篇
杨充
2026-05-27
目录

进程与多进程优化

# 进程模型与多进程优化

本文核心命题:进程是"隔离单元,也是性能边界"——进程提供地址空间隔离 + 故障隔离 + 资源隔离,但代价是 IPC 开销 + 启动开销 + 内存浪费。一切多进程优化都是在"隔离收益"与"通信 / 启动 / 内存代价"之间找平衡点。


# 01.阅读说明

  • 本文卷归属:卷二 · 资源篇 · 第 5 篇
  • 本文目标层级:L3 专家 → L4 架构
  • 适用平台:Android(主) / iOS / Web(多 Tab + Service Worker) / 嵌入式
  • 前置阅读:
    • 卷二·04 线程模型与调度优化(进程 vs 线程的对比)
    • 卷二·03 OOM 异常与低内存治理(多进程是 OOM 隔离重要手段)

全文 21 章地图:

   §01 阅读说明           §02 贯穿案例           §03 进程物理本质     §04 隔离与通信原理
   §05 度量与采集         §06 归因决策树
   §07 进程创建全链路 ⭐  §08 IPC 通信全链路 ⭐  §09 共享内存全链路 ⭐
   §10 进程生命周期全链路 ⭐  §11 跨端进程对照 ⭐  §12 跨端对照
   §13 治理一层数量 ⭐    §14 治理二层 IPC ⭐   §15 治理三层隔离 ⭐   §16 治理四层重启 ⭐
   §17 求证实验 ⭐         §18 实战案例           §19 防劣化体系          §20 跨平台速查
   §21 总结与延伸
1
2
3
4
5
6
7

阅读建议:先读 §02 案例 → §03/§04 拿到原理 → §05/§06 学会度量归因 → §07-§11 五个全链路(创建/IPC/共享/生命周期/跨端)→ §13-§16 四层治理(数量收敛/IPC/隔离/重启)→ §17 求证 → §18-§20 工程闭环。


# 02.贯穿案例

本案例贯穿全文:§03 看懂代价、§04 拿到隔离模型、§05/§06 用三方案+决策树定位、§17 用实验复盘、§13-§16 给出分层策略闭环。

# 2.1 案例背景

某头部金融 App V8.5 历史上沿用"5 进程架构"(主进程 / Push 进程 / WebView 进程 / 守护进程 / 推送拉活进程),架构师初心是"模块隔离防崩溃"。但近期问题集中爆发:

  • 常驻 PSS 达 420MB(主 220 + Push 80 + WebView 60 + 守护 35 + 拉活 25),中端机 OOM 率 4.8%。
  • 冷启动 P95 = 3.6s(用户从 Push 点入是冷启动率 38%)。
  • Android 11+ 升级后被系统认定"贪婪应用",主进程被杀率从 2% 飙到 18%。
  • 应用商店"卡顿"差评/月 12,000+,用户流失加速。

研发组初步反应:"拆进程是为了稳定,不能改架构。"——这是典型的"架构惯性"。

# 2.2 经验派的 5 周折腾(典型反面教材)

周次 动作 结果
第 1 周 加强双进程互拉保活(怀疑被杀太多) 主进程被杀率反升到 22%(系统更激进打压)
第 2 周 把 Push 进程内存上限调小(怀疑 Push 占内存) Push 频繁 OOM,消息丢失率涨 8 倍
第 3 周 加更多 IPC 缓存层(怀疑 IPC 慢) IPC 抽象层 bug 引发数据不一致
第 4 周 把 WebView 进程预热常驻(怀疑冷启慢) 常驻内存又涨 30MB
第 5 周 改 Push 进程优先级(怀疑被低优先级杀) 无明显改善

复盘:五周折腾的根本错误是默认"5 进程不能动"。所有动作都在"修补 5 进程架构",没人质疑"5 个进程真的都必要吗"。进程是重资源,每个都要算清成本收益。

# 2.3 方法派的 8 天闭环

新接手的同学按本文方法论重做:

Day 1(§04 第一性原理 + §05 三方案):

  • 进程清单:5 个进程清晰列出,各自 PSS。
  • 资源监控:Push 进程 80MB,但实际只有每天 8-12 次推送时干活,其余 23.5 小时空转。
  • IPC trace:主→Push、主→守护进程的 Binder 调用每秒 35 次(多数是状态心跳)。

Day 2(§06 归因决策树):逐进程评估:

进程 必要性 真实工作量 占用
主进程 必要 全程 220MB
Push 进程 不必要 每天 8-12 次×几秒 80MB(23.5h 空转)
WebView 进程 必要 风险隔离(H5 业务多) 60MB
守护进程 不必要 仅为保活(A11+ 失效) 35MB
拉活进程 不必要 仅为保活 25MB

→ 5 进程中 3 个是"为了保活"或"过度隔离"开的,可以直接删。

Day 3(§17.3 实验数据支持):用本文的保活实验数据说服架构师——"双进程互拉在 A11+ 几乎全失效"。

Day 4-5(§13-§16 分层策略):

  • 第 1 层(数量收敛):Push 改 FCM 系统级推送;守护/拉活直接删;保留 WebView 进程做风险隔离。
  • 第 2 层(IPC 治理):剩余主↔WebView 的 IPC 高频心跳改批量+缓存;大数据用共享内存。
  • 第 3 层(风险隔离):WebView 进程仍单独,确保 H5 崩不影响主。
  • 第 4 层(拥抱重启):投入"快速重启 + 状态恢复"——被杀后 < 800ms 拉起,且滚动位置/草稿/登录态全恢复。

Day 6(§17.5 实验思路验证):构造"被杀-重启-恢复"自动化用例。

Day 7-8(灰度 + 上线):

# 2.4 上线效果

指标 经验派 5 周后 方法派 8 天后
进程数 5 2(主 + WebView)
常驻 PSS 450MB 240MB(-47%)
冷启 P95 3.6s 1.2s
中端机 OOM 率 4.8% 0.6%
主进程被杀率 22% 3%(不再被打压)
推送到达率(FCM) 91% 97%
用户主动回归率 -8% +5%

核心洞察:经验派 5 周错在"把架构当宪法"。进程治理的最大杠杆是删除非必要进程,而不是优化它们。删 3 个进程让常驻内存降 47%,被杀率反而从 22% 降到 3%——系统不再把你当贪婪应用,是最大的奖励。

# 2.5 案例如何串起本文

  • §03 现象与代价 ▶▶ 业务损失映射:差评/月 12K、用户流失加速。
  • §04 隔离 vs 通信 ▶▶ 案例 3 个进程是"过度隔离",2 个是"合理隔离"。
  • §07-§11 五大全链路 ▶▶ 创建/IPC/共享/生命周期/跨端 五条链路对应案例每一类问题。
  • §17 求证实验 ▶▶ §17.1 启动代价、§17.2 IPC 吞吐、§17.3 保活失效、§17.5 快速重启都在案例中变现。
  • §13-§16 四层治理 ▶▶ "数量收敛→IPC 治理→风险隔离→快速重启"四层正是案例落地路径。

探索性思考:为什么"架构惯性"是工程团队最危险的认知陷阱?因为架构往往是几年前的决策,由资历最老的工程师定的——质疑架构等于质疑权威。但系统在变(Android 11+ 打压贪婪),几年前合理的决策今天可能是负担。真正的工程精神是"持续质疑前提" —— 包括质疑自己当初的设计。


# 03.进程物理本质

# 3.1 一句话定义

进程 = 操作系统资源分配与隔离的基本单元,是"拥有独立地址空间 + 文件句柄 + 信号上下文"的执行实例。

这句话隐含三个不可商量的物理约束:

约束一:进程是地址空间的边界

每个进程拥有独立的虚拟地址空间。这是硬隔离:进程 A 不可能访问到进程 B 的内存(除非通过 IPC 显式共享)。

这是进程"安全"的根本:

  • 进程 A 崩溃不会破坏进程 B 的内存(故障隔离)
  • 进程 A 的内存泄漏不会影响进程 B(资源隔离)
  • 进程 A 不可能读取进程 B 的私密数据(安全隔离)

代价:进程间通信必须经过内核(copy 或 mmap),有性能开销。

约束二:进程创建有固定成本

每次创建进程都要做:

  • 分配地址空间(页表)
  • 复制或映射代码段
  • 加载动态库(dyld / linker)
  • 启动运行时(VM / Native)
  • 执行入口函数
   Android Zygote fork:     ~200-400ms(共享 ART,省去 VM 启动)
   iOS exec:               ~200-300ms(每次都要 dyld + libObjC)
   Web 新 Tab:             ~100-500ms(视浏览器实现)
   Linux fork+exec:        ~10-100ms(不含应用初始化)
1
2
3
4

这就是为什么 Android 用 Zygote 模型 fork:共享父进程的 ART,省去每次都重启 VM 的 ~500ms 开销。

约束三:进程间通信必经内核

任何 IPC 形式(Binder / Pipe / Socket / Shared Memory)都要经过内核:

   进程 A 用户态 ──[陷入内核]──▶ 内核中转 ──[切回用户态]──▶ 进程 B 用户态
        │                              │
     一次 syscall                   一次 syscall
     ~1-5μs                        ~1-5μs
1
2
3
4

即使是"零拷贝"的 Shared Memory,初次建立映射仍需 syscall。这是 IPC 的物理底线。

# 3.2 现象与代价

进程问题往往体现为系统级问题:

  • 多进程内存浪费:同一应用拆 5 个进程,每个进程都有自己的 ART / 资源副本,内存涨 2-3 倍。
  • 进程拉起慢:用户从通知点入应用 → 主进程被杀 → 重新冷启动 → 体验类崩溃。
  • IPC 延迟过高:跨进程查询数据 100ms+,用户感知"卡"。
  • 保活滥用导致系统体验差:多个 App 互相拉活,整机内存吃紧、温度升高。
  • 多进程崩溃定位难:插件进程崩溃,主进程无感,但功能失效。

业务代价(行业实测数据):

  • 头部 App:减少不必要进程后,内存峰值下降 40-60%,OOM 率下降 30%。
  • 进程被杀后冷启动时长是热启的 5-10 倍。
  • 系统对"多进程贪婪"应用的 OOM 倾向更高(LMK 评分更差)。

▶▶ 回扣 §02 案例:金融 App 5 进程架构常驻 PSS 450MB → 删到 2 进程 240MB(-47%),OOM 率 4.8%→0.6%。

# 3.3 度量准则与基准

资源视角(USE):

指标 含义 阈值参考
应用进程数 总和 < 3(普通) / < 5(重型)
单进程 PSS 占设备 RAM 比例 主 < 30%、子 < 10%
IPC 错误 调用失败率 < 0.1%

请求视角(RED):

指标 含义 阈值参考
IPC 延迟 跨进程调用时长 < 5ms(本地)/ < 50ms(重型)
进程拉起时长 从拉起到 onCreate 完成 < 800ms
保活成功率 主进程被杀后多久重新拉起 视场景

行业基准:

平台 应用进程数 IPC 延迟 进程启动开销
Android 1-3 主用 + 偶尔子 Binder 同步 < 5ms 200-500ms(fork from Zygote)
iOS 几乎单进程(特殊扩展才多) XPC < 10ms 200ms+(exec + dyld)
Web 每 Tab 一个进程 postMessage < 10ms 100-500ms
嵌入式 Linux 视设计 DBus / Unix Socket varies

# 3.4 反直觉问题清单

带着这些问题阅读:

  1. 多进程一定比单进程慢吗?
  2. 拆进程能解决 OOM 吗?拆多少合适?
  3. Binder 跨进程一次调用比同进程慢多少?
  4. iOS 几乎单进程,是不是就没"进程问题"?
  5. Web Worker 是进程还是线程?
  6. 保活做得好就能"不被杀"吗?
  7. 进程间共享内存(SharedMemory)真的"零拷贝"吗?
  8. 子进程崩溃为什么主进程也可能被影响?

探索性思考:为什么"进程"是工程师最容易"误用"的抽象?因为它的隔离收益是"不出问题时看不到"——但代价(内存翻倍、IPC 延迟)是"立刻能感受到"。正常情况下进程隔离的价值为零,异常情况下价值无限——这种非线性收益让权衡变得困难。好的进程设计需要"概率思维":评估隔离的"事件价值 × 发生概率" vs 通信的"日常成本"。


# 04.隔离与通信原理

# 4.1 隔离收益 vs 通信代价

进程的本质收益是"隔离",本质代价是"通信"。所有多进程设计都在权衡这两者:

   ┌────────────────────────────────────────────────┐
   │ 隔离收益                                        │
   │ - 故障隔离(子进程崩溃,主进程不受影响)          │
   │ - 内存隔离(子进程内存大不影响主进程)            │
   │ - 安全隔离(沙箱 / 权限独立)                    │
   ├────────────────────────────────────────────────┤
   │ 通信代价                                        │
   │ - IPC 延迟(每次调用 1-50ms)                    │
   │ - 数据序列化开销(Parcel / Codable)             │
   │ - 内存浪费(每个进程独立的运行时 / 资源副本)      │
   │ - 启动开销(200-500ms 冷启动)                    │
   └────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12

# 4.2 典型多进程设计模式

   ┌──────────────────────────────────────────┐
   │ A. 单进程(主流)                          │
   │    所有功能在主进程,无 IPC               │
   │    优点:无 IPC 开销                      │
   │    缺点:一处崩溃全死                      │
   ├──────────────────────────────────────────┤
   │ B. 主进程 + 风险隔离                       │
   │    主进程 + Web 内核进程 / 视频解码 / 推送 │
   │    优点:风险代码不会拖垮主进程            │
   │    缺点:IPC 开销可控                      │
   ├──────────────────────────────────────────┤
   │ C. 主进程 + 守护 / 保活                    │
   │    主进程 + 守护进程(互相拉起)          │
   │    优点:增加保活成功率(Android)         │
   │    缺点:被系统打压、用户反感              │
   ├──────────────────────────────────────────┤
   │ D. 插件化 + 进程隔离                       │
   │    各业务在独立进程                       │
   │    优点:彻底解耦                          │
   │    缺点:内存翻倍,IPC 复杂                │
   └──────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

关键认知:

  • 大多数应用只需 A(单进程)
  • B 是合理的折中(风险代码隔离)
  • C 在 Android 8+ 后基本失效(系统强力打压)
  • D 仅超大型应用使用(如微信、支付宝 30+ 进程)

▶▶ 回扣 §02 案例:金融 App 的 5 进程架构本质是 B + C + 过度拆——主+WebView 是合理 B;守护/拉活是失效的 C;Push 进程是过度拆。80% 应用应该用 A,少数用 B,几乎没人需要 C。

# 4.3 跨平台同构原理

底层都是 POSIX fork() 或其衍生(Windows CreateProcess),上层封装不同。

跨平台术语对照

通用术语 Android iOS Web C/C++
进程创建 Zygote fork exec / posix_spawn Tab / Worker 进程 fork
IPC 同步 Binder / Messenger NSXPCConnection postMessage Pipe / Socket
共享内存 MemoryFile / ASharedMemory mmap SharedArrayBuffer shm_open
子进程 <service android:process=":xxx"> App Extension Web Worker / iframe fork
守护 JobScheduler / WorkManager Background Task Service Worker systemd
进程上限 取决于 ROM 严格(前台 1 + 扩展若干) 视浏览器 视 OS

# 4.4 平台差异点矩阵

维度 Android iOS Web C/C++ Linux
默认模式 单进程为主,可显式拆 强制单进程(仅 Extension) 每 Tab 一个 自由
IPC 机制 Binder(高性能) XPC postMessage Pipe / Socket / shm
Binder 性能 同步 < 5ms XPC 同步 < 10ms postMessage < 10ms varies
共享内存 MemoryFile(ashmem) mmap SharedArrayBuffer shm
启动开销 200-400ms(Zygote) 200-300ms 100-500ms 10-100ms
保活限制 8.0+ 严格 严格(仅特定模式) Service Worker 有时限 视系统

探索性思考:为什么"四种多进程设计模式"在工程上有稳定划分?因为它们对应"隔离需求 × 通信频率"的四个象限。好的抽象划分通常对应物理本质 —— A/B/C/D 不是被发明的,而是被发现的。多数应用属于 A 是因为通信成本远大于隔离收益 —— 这是工程上的物理事实,不是个人偏好。


# 05.度量与采集

# 5.1 三类采集方案

   ① 进程清单采集(多少个进程,各多大)
   ② IPC 调用采集(频次、延迟、数据量)
   ③ 进程生命周期采集(拉起、被杀、ProcessExitReason)
1
2
3

① 进程清单采集

// Android:扫 ActivityManager.RunningAppProcesses
fun listAppProcesses(): List<ProcessInfo> {
    val am = context.getSystemService(ActivityManager::class.java)
    return am.runningAppProcesses?.filter { 
        it.uid == android.os.Process.myUid() 
    }?.map {
        ProcessInfo(it.processName, it.pid, getPss(it.pid))
    } ?: emptyList()
}
1
2
3
4
5
6
7
8
9

② IPC 调用采集

平台 工具
Android Perfetto Binder Trace
iOS Instruments XPC
Web Performance Panel postMessage

③ 进程生命周期采集

// Android 11+
val am = context.getSystemService(ActivityManager::class.java)
val reasons = am.getHistoricalProcessExitReasons(null, 0, 100)
reasons.forEach {
    upload(it.reason, it.processName, it.pss, it.timestamp)
}
1
2
3
4
5
6

# 5.2 各方案的可见盲区

方案 钩子位置 数据粒度 性能开销 跨端通用性 线上可用 主要局限
① 进程清单 ActivityManager 进程级 极低 跨端有差异 是 不知 IPC
② IPC trace 系统级 调用级 中 部分平台 部分 离线分析
③ 退出原因 系统 API 事件级 极低 Android 11+ 是 平台限定

# 5.3 跨平台采集对照表

平台 进程清单 IPC 采集 生命周期
Android ActivityManager Perfetto getHistoricalProcessExitReasons
iOS sysctl Instruments terminationReason
Web chrome://process-internals Performance Panel (无标准)

# 5.4 数据可信度评估

  • 进程清单:可信度高,但只看现状。
  • IPC trace:可信度高,但开销中。
  • 退出原因:可信度极高,是关键。

探索性思考:为什么"进程退出原因"是 Android 11 才提供?因为之前应用只能"看到自己醒着"——醒来发现自己刚被杀了,但不知道为什么。这是平台演进的真实写照:用户的痛点驱动新 API。Android 11 的 ProcessExitReason 是工程上的"福音",让"被杀分类治理"成为可能。


# 06.归因决策树

# 6.1 进程问题决策树

   症状 = ?
      │
      ├─ 常驻内存高(PSS > 300MB)
      │     │
      │     └─ 走"进程数过多"分支:
      │        - 列出所有进程及其用途
      │        - 删除非必要进程(§13.1)
      │
      ├─ 主进程频繁被杀
      │     │
      │     └─ 走"被杀原因"分支:
      │        - getHistoricalProcessExitReasons
      │        - LMK / ANR / Force Stop / Crash
      │        - 治理:减进程 + 升优先级 + 修崩溃
      │
      ├─ IPC 慢(> 50ms)
      │     │
      │     └─ 走"IPC 性能"分支:
      │        - 数据量大 → 共享内存(§14.3)
      │        - 频次高 → 批量化 + 缓存(§14.1-14.2)
      │
      └─ 启动慢
            │
            └─ 走"进程冷启"分支:
               - 如果是子进程被频繁拉起 → 改常驻
               - 如果是主进程冷启 → 见冷启动篇
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 6.2 IPC 性能归因

IPC 慢的典型根因:

  1. 数据量过大(> 100KB 应该用共享内存)
  2. 频次过高(每秒 100+ 次需批量化)
  3. 同步阻塞主线程(应改 oneway 异步)
  4. 跨进程拉起子进程(启动 ~200ms)

# 6.3 进程拉起归因

子进程频繁拉起的典型原因:

  • ContentProvider 跨进程查询
  • 闹钟 / Push 唤醒
  • 系统广播触发
  • 第三方 SDK 主动唤醒

# 6.4 内存共享归因

多进程内存浪费来源:

  • 每个进程独立的 ART/Dalvik VM
  • 每个进程独立的 .so 副本(部分共享但有限)
  • 每个进程独立的资源缓存

探索性思考:为什么"决策树"在进程归因上特别有效?因为进程问题的症状-根因映射是一对一的——内存高就是进程多,IPC 慢就是数据大或频次高。结构化的领域决策树足够 ML 不必要——这是工程归因的常态。


# 07.进程创建全链路

# 7.1 Android Zygote fork 全链路

   ① 系统启动 → Zygote 进程启动
      ↓ 加载 ART + 通用类(耗时 ~3s,仅一次)
   ② Zygote 监听 socket
      ↓
   ③ 应用启动 → AMS 通过 socket 通知 Zygote
      ↓ "fork 一个进程,跑 com.example.MyApp"
   ④ Zygote 调用 fork()
      - 复制页表(COW,不复制内存)
      - 子进程继承 ART + 已加载的类
      ↓
   ⑤ 子进程进入 ActivityThread.main()
      - 设置进程标识 / UID
      - 创建 Application
      - 调用 Application.attachBaseContext + onCreate
      ↓
   ⑥ 启动 Activity / Service / 接收 IPC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

关键开销分解:

   ① Zygote socket 接收命令      ~5ms
   ② fork(copy 页表)           ~20ms
   ③ 设置进程标识 / 安全策略     ~20ms
   ④ 启动 ActivityThread.main   ~50ms
   ⑤ Application.attachBaseContext + onCreate ~100ms+
   ─────────────────────────────
   总计 ~200ms+
1
2
3
4
5
6
7

优化机会:

  • Application.onCreate 是大头(业务初始化)
  • 见 卷四·01 冷启动

# 7.2 iOS posix_spawn 全链路

iOS 没有 Zygote,每次 exec 都要重新加载 dyld + libObjC。

   ① 进程创建(posix_spawn)       ~10ms
   ② dyld 加载所有 dylib            ~100ms
   ③ libObjC 初始化                ~50ms
   ④ +load + static initializer     ~50ms+
   ─────────────────────────────
   总计 ~210ms+
1
2
3
4
5
6

iOS 优化路径:

  • 减少 dylib 数量(动态库链接)
  • 减少 +load 方法(用 +initialize 延迟)
  • 减少 static initializer
  • 见 dyld closures(iOS 13+)

# 7.3 Web 新 Tab 全链路

   ① 浏览器主进程 fork(或 spawn)渲染进程
      ↓
   ② V8 Isolate 启动(~50ms)
      ↓
   ③ 加载 HTML + 执行 JS
      ↓
   ④ 首屏渲染
1
2
3
4
5
6
7

Web 特殊性:

  • 每个 Tab 独立进程(部分浏览器)
  • iframe 跨域时也独立进程
  • Service Worker 是独立进程

# 7.4 Linux fork+exec 全链路

   ① fork() ~5ms(COW 页表复制)
      ↓
   ② exec() 加载新二进制
      ↓
   ③ 动态链接 ld-linux ~10ms
      ↓
   ④ libc 初始化
      ↓
   ⑤ main()
   ─────────────────────────────
   总计 ~10-100ms(不含应用初始化)
1
2
3
4
5
6
7
8
9
10
11

# 7.5 跨端进程创建对照

平台 创建方式 启动时长 优化空间
Android Zygote fork 200-400ms 减 Application onCreate
iOS posix_spawn 200-300ms 减 dylib + +load
Web Tab spawn 100-500ms 减 JS 初始化
Linux fork+exec 10-100ms 减动态链接

▶▶ 回扣 §02 案例:Push 进程被频繁拉起(每天 8-12 次×几秒),每次 ~200ms 启动开销。改 FCM 系统级推送后,这些 ~200ms 全部消失。进程启动是重资源,频繁拉起是反模式。

探索性思考:为什么 Android 选择 Zygote 而 iOS 选择 exec?因为两者的应用模型不同——Android 应用是 Java/Kotlin(需要 VM),iOS 应用是原生代码(无 VM)。Zygote 模式的本质是"分摊昂贵的初始化" —— ART 启动一次后被所有应用共享。好的架构通常对应"识别共享成本"。


# 08.IPC 通信全链路

# 8.1 Android Binder 全链路

   ① 进程 A 调用 IRemoteService.method()
      ↓ AIDL 生成的 Stub
   ② 参数 marshal 到 Parcel
      ↓
   ③ ioctl(BINDER_WRITE_READ)
      → 陷入内核 Binder driver
      ↓
   ④ Binder driver 从 A 拷贝到 B 进程内存
      ↓ (一次拷贝,比 socket 快 2×)
   ⑤ 进程 B 的 Binder 线程被唤醒
      ↓
   ⑥ Stub 反序列化 + 调用实际方法
      ↓
   ⑦ 返回值 marshal + ioctl 返回
      ↓
   ⑧ 进程 A 反序列化结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

关键性能数据:

  • 单次调用 ~3μs base + 拷贝
  • 100B 数据 ~4μs(250K op/s)
  • 1KB 数据 ~6μs(180K op/s)
  • 1MB 数据 ~10ms(100 op/s)

# 8.2 iOS XPC 全链路

   ① 进程 A 创建 NSXPCConnection
      ↓
   ② 通过 launchd 启动目标 service
      ↓
   ③ 调用方法(自动序列化)
      ↓
   ④ 通过 mach IPC 传递
      ↓
   ⑤ 进程 B 反序列化 + 执行
      ↓
   ⑥ 返回结果
1
2
3
4
5
6
7
8
9
10
11

XPC 特性:

  • 基于 mach 端口 + libdispatch
  • 自动管理 service 生命周期
  • 类型安全(NSSecureCoding)

# 8.3 Web postMessage 全链路

   ① 主线程 worker.postMessage(data)
      ↓
   ② 浏览器结构化克隆数据(深拷贝)
      ↓
   ③ 跨进程传递
      ↓
   ④ Worker 端 onmessage 接收
      ↓
   ⑤ 数据反序列化(已是新对象)
1
2
3
4
5
6
7
8
9

Web postMessage 特殊性:

  • 默认深拷贝(开销大)
  • 可用 Transferable 转移所有权(零拷贝)
  • 可用 SharedArrayBuffer 真正共享

# 8.4 IPC 选型决策

   数据量大小:
   ├─ < 1KB → 直接 IPC(任何方式)
   ├─ 1KB-100KB → IPC 但要批量化
   ├─ 100KB-1MB → 共享内存或谨慎 IPC
   └─ > 1MB → 必须共享内存
   
   调用频次:
   ├─ < 10/s → 任意方式
   ├─ 10-100/s → 批量化
   └─ > 100/s → 主进程缓存 + 变更 push
1
2
3
4
5
6
7
8
9
10

# 8.5 跨端 IPC 性能对照

数据大小 Android Binder iOS XPC Web postMessage
100B 220K op/s 180K op/s 90K op/s
1KB 180K op/s 150K op/s 80K op/s
10KB 65K op/s 55K op/s 35K op/s
100KB 9K op/s 7K op/s 5K op/s
1MB 950 op/s 700 op/s 500 op/s

▶▶ 回扣 §02 案例:主→Push、主→守护进程的 Binder 调用每秒 35 次(多数是状态心跳),看似不多,但累积到一天就是 300 万次——每次 4μs 也是几十秒 CPU 时间的浪费。IPC 频次比 IPC 单次开销更重要。

探索性思考:为什么 Binder 比 socket 快 2×?因为 Binder 用了"一次拷贝"——内核直接 mmap 接收方进程内存。Binder 的设计是"为 Android 量身定制" —— 它假设 IPC 是高频核心场景,所以专门优化。好的系统设计来自"理解高频路径"。


# 09.共享内存全链路

当 IPC 数据量超过 100KB 时,必须用共享内存。理解共享内存的全链路是性能优化的关键。

# 9.1 Android SharedMemory 全链路

   ① 进程 A 创建:
      SharedMemory.create("name", size)
      ↓ ashmem 内核驱动分配匿名内存
   ② 通过 Binder 传递 SharedMemory 句柄
      ↓
   ③ 进程 B 接收句柄:
      shm.mapReadOnly()
      ↓ mmap 到 B 进程地址空间
   ④ B 进程像普通内存一样访问
      ↓ 零拷贝(A 和 B 看到同一物理页)
   ⑤ A 修改 → B 立即可见(需同步原语保证一致性)
1
2
3
4
5
6
7
8
9
10
11

关键特性:

  • 物理内存共享(零拷贝)
  • 支持 Read/Write/Execute 权限位
  • 进程 A 死亡后 B 仍可访问(直到都释放)

典型用例:

  • 大图片传输(位图)
  • 视频帧
  • 大配置数据
  • 大日志缓冲区

# 9.2 iOS mmap 全链路

   ① 进程 A 创建文件(或 anonymous):
      shm_open("name", O_CREAT)
      ↓
   ② 设置大小 ftruncate
      ↓
   ③ mmap 映射到地址空间
      ↓
   ④ 通过 XPC 传递文件句柄
      ↓
   ⑤ 进程 B mmap 同一文件
      ↓
   ⑥ 两进程访问同一物理页
1
2
3
4
5
6
7
8
9
10
11
12

iOS 共享内存限制:

  • 仅特定 entitlement 才允许
  • App 沙箱默认禁止跨 App 共享内存
  • 同 App 内 Extension 之间可以

# 9.3 Web SharedArrayBuffer 全链路

   ① 主线程:
      const sab = new SharedArrayBuffer(1024 * 1024)
      ↓
   ② 通过 postMessage(sab) 传递
      ↓ Worker 收到后两边访问同一 buffer
   ③ 用 Atomics 同步:
      Atomics.add(view, 0, 1)
      Atomics.wait(view, 0, oldValue)
1
2
3
4
5
6
7
8

Web 安全限制:

  • 需要 cross-origin isolation(COOP+COEP headers)
  • 部分浏览器默认禁用
  • 是 Spectre 漏洞缓解后逐步恢复的特性

# 9.4 共享内存同步问题

关键挑战:进程 A 写、进程 B 读,如何保证一致性?

手段:

  • 跨进程 mutex(pthread_mutex_t with PTHREAD_PROCESS_SHARED)
  • 原子操作(Atomic / Atomics)
  • ring buffer(无锁单生产者单消费者)
  • 版本号 + 双缓冲

# 9.5 跨平台共享内存对照

平台 API 启动开销 同步原语 限制
Android SharedMemory(API 27+)/ MemoryFile ~1ms 自管 App 内
iOS shm_open + mmap ~1ms 自管 Entitlement
Web SharedArrayBuffer + Atomics ~ms Atomics COOP/COEP
Linux shm_open + mmap ~1ms 自管 自由

探索性思考:为什么"零拷贝"是个工程神话?因为它隐藏了首次建立 mmap 的开销(~1ms)和同步原语的开销。少量大数据传输用共享内存反而比 Binder 慢 —— 因为建立成本无法摊销。"零拷贝"只在"高频大数据"场景下成立 —— 这是工程实战的真实约束。


# 10.进程生命周期全链路

# 10.1 Android 进程生命周期全链路

   ① 应用启动 → Zygote fork
      ↓
   ② 进程进入 RUNNING 状态
      ↓
   ③ Activity 切换 / 后台 → oom_adj 分数变化
      - 前台 0
      - 可见 100
      - 服务 500
      - 后台 700
      - 缓存 906
      ↓
   ④ 系统内存压力大 → LMK 选择高分进程杀掉
      ↓
   ⑤ 进程终止
      ↓
   ⑥ 用户切回 / 推送等触发拉起
      → goto ①
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 10.2 iOS 进程生命周期全链路

   ① 应用启动 → posix_spawn
      ↓
   ② 进程 active(前台)
      ↓
   ③ 切后台 → applicationDidEnterBackground
      - 5 秒内必须完成清理
      ↓
   ④ 进入 suspended 状态
      ↓
   ⑤ 系统内存压力 → jetsam 杀掉
      ↓
   ⑥ 用户切回 → 重新启动
1
2
3
4
5
6
7
8
9
10
11
12

iOS 特殊性:

  • 后台 5 秒生死线
  • 特定模式可继续后台(VoIP / location)
  • BGTask API 提供合规后台执行

# 10.3 Web Tab 生命周期全链路

   ① 用户打开 Tab → 进程 spawn
      ↓
   ② Tab 活跃 → 全速运行
      ↓
   ③ Tab 切到后台 → 节流(rAF 减到 1/s)
      ↓
   ④ 系统内存压力 → Tab Discarded
      ↓
   ⑤ 用户切回 → 重新加载(visibilitychange 'load' 事件)
1
2
3
4
5
6
7
8
9

# 10.4 ProcessExitReason 解读

Android 11+ 提供详细被杀原因:

原因 含义 治理方向
REASON_LOW_MEMORY LMK 杀 减内存 / 减进程
REASON_ANR ANR 触发 见 ANR 篇
REASON_USER_REQUESTED 用户主动杀 优化体验
REASON_USER_STOPPED 系统决定 配合系统
REASON_INITIALIZATION_FAILURE 启动失败 修崩溃
REASON_PERMISSION_CHANGE 权限变更 权限处理
REASON_EXCESSIVE_RESOURCE_USAGE 资源超限 减资源
REASON_CRASH 崩溃 修崩溃
REASON_CRASH_NATIVE Native 崩溃 修 native

# 10.5 跨平台生命周期对照

平台 主要状态 系统杀机制 应用预警
Android foreground/visible/background/cached LMK onTrimMemory
iOS active/background/suspended jetsam memoryWarning
Web foreground/background Tab Killer visibilitychange

探索性思考:为什么 Android 11 才补上"被杀原因"API?因为之前应用只能"猜测"被杀原因——是 LMK?ANR?还是用户杀的?模糊的诊断信息让 OOM 治理只能"试错" —— 直到 ProcessExitReason API 出现,才有了"分类施治"的基础。好的 API 让正确的工程实践成为可能。


# 11.跨端进程对照

# 11.1 Android 多进程模式

典型架构:

   主进程(com.example.app)
      ├─ ":webview"(H5 隔离)
      ├─ ":push"(推送服务)
      ├─ ":daemon"(守护,已基本失效)
      └─ ":sdk"(第三方 SDK 隔离)
1
2
3
4
5

配置方式:

<service android:name=".PushService"
    android:process=":push" />
1
2

# 11.2 iOS App Extension 模式

iOS 强制单进程,但提供 Extension:

Extension 类型 用途
Today Widget 通知中心小部件
Share Extension 分享菜单
Action Extension 操作菜单
Photo Editing 照片编辑
Custom Keyboard 自定义键盘
Notification Service 通知扩展
iMessage App iMessage 扩展

Extension 特性:

  • 独立进程,独立内存限制(30-50MB)
  • 通过 App Group 共享数据
  • 通过 XPC 通信

# 11.3 Web 多进程模式

   浏览器主进程
      ├─ 渲染进程(每 Tab 一个,部分共享)
      ├─ GPU 进程
      ├─ 网络进程
      └─ Service Worker 进程
1
2
3
4
5

Site Isolation:

  • Chrome 默认每个站点独立进程
  • iframe 跨域时也独立
  • 防御 Spectre 漏洞

# 11.4 跨端框架的进程模型

Flutter:

  • 所有 Dart 代码在主进程的 Flutter Engine 中
  • 平台插件通过 MethodChannel(同进程)

React Native:

  • JS 在主进程的 JS 线程
  • Native 模块同进程

Hybrid(WebView):

  • Android 可启用 WebView 多进程
  • iOS WKWebView 默认进程外

# 11.5 跨端进程模式对照

框架/平台 默认进程数 隔离能力 推荐场景
Android Native 1(可显式拆) 强 任何场景
iOS Native 1(仅 Extension) 中(Extension) 任何场景
Flutter 1 弱(同进程) 跨端业务
RN 1 弱 跨端业务
Web 每 Tab 1 个 强(默认) Web 应用

探索性思考:为什么 iOS 强制单进程而 Android 允许多进程?这反映了两个平台的设计哲学——iOS 假设"应用应该简洁",Android 假设"应用可能复杂"。简洁的代价是缺少灵活性,灵活的代价是被滥用。iOS 没有"进程膨胀"问题,因为根本没法膨胀 —— 限制有时是恩赐。


# 12.跨端对照

# 12.1 五个全链路总览

链路 Android iOS Web Linux
进程创建 Zygote fork posix_spawn Tab spawn fork+exec
IPC 通信 Binder XPC postMessage Pipe/Socket
共享内存 SharedMemory mmap SharedArrayBuffer shm
生命周期 LMK + oom_adj jetsam Tab Killer OS 调度
跨端模式 多进程灵活 Extension only Tab + Worker 自由

# 12.2 各平台优化优先级

Android:

  1. 删除非必要进程
  2. WebView 多进程(H5 业务多时)
  3. IPC 批量化 + 主进程缓存
  4. 大数据用 SharedMemory
  5. 放弃保活,拥抱 WorkManager + 快速重启

iOS:

  1. 减少 dylib + +load(启动加速)
  2. App Group + UserDefaults 共享
  3. BGTask 替代保活
  4. Extension 内存严控(< 30MB)

Web:

  1. Site Isolation 利用
  2. Web Worker 处理 CPU 密集
  3. SharedArrayBuffer + Atomics(高性能场景)
  4. Service Worker 离线缓存

# 12.3 反直觉问题答疑

问题 答案
多进程比单进程慢吗? 可能,IPC 开销大于隔离收益时是
拆进程能解决 OOM 吗? 部分。子进程隔离能防主进程 OOM,但总内存增加
Binder vs 同进程慢多少? 单次调用 ~3μs vs 函数调用 ns 级,3 个量级
iOS 没"进程问题"? 不全是。Extension 内存限制是新挑战
Worker 是进程还是线程? Web Worker 通常是线程;Service Worker 是进程
保活做好就不被杀? 错。Android 11+ 暗保活几乎全失效
SharedMemory 真零拷贝? 建立后零拷贝,但建立有开销
子进程崩溃影响主进程? 通常不会,但会留下僵尸状态

▶▶ 回扣 §02 案例:经验派 100% 命中"反直觉问题"——把"保活"当万能药。真相是:现代 OS 设计就是"打压贪婪应用",硬抗系统是低 ROI 工作。


# 13.治理一层数量

核心命题:进程治理的最大杠杆是删除非必要进程。这一层不是"如何拆",而是"为什么不能拆"。

# 13.1 逐进程价值评估表

机理:用统一格式逐进程评估,把"模糊架构"变成"可量化决策"。

评估模板:

| 进程名 | 真实工作时长占比 | 内存占用 | 必要性等级 | 决策 |
| 主进程 | 100% | 200MB | 必要 | 保留 |
| Push 进程 | < 0.5%(每天 8-12 次)| 80MB | 不必要(可合并)| 删除 |
| 守护进程 | 0%(仅为保活,A11+ 失效)| 35MB | 无效 | 删除 |
| WebView 进程 | 30% | 60MB | 必要(风险隔离)| 保留 |
1
2
3
4
5

收益:§02 案例5→2 进程,PSS -47%。

边界:评估需架构师参与;删除进程涉及业务方协调。

# 13.2 Push 进程合并到主进程

机理:现代推送通道(FCM/APNs/华为/小米推送)都是系统级,应用层不需要自己保持长连接进程。

代码(FCM):

class MyFCMService : FirebaseMessagingService() {
    override fun onMessageReceived(message: RemoteMessage) {
        // 直接在主进程接收,无需独立进程
        handlePush(message.data)
    }
}
1
2
3
4
5
6

收益:节省 50-80MB 常驻内存;推送到达率反而升(FCM 比自建长连接稳定)。

边界:海外用 FCM,国内用厂商推送+融合 SDK;自建长连接仅 IM 等强实时业务。

# 13.3 删除守护/拉活进程

机理:§17.3 实验双进程互拉 A11+ 几乎全失效;占内存还被系统打压。

代码:直接删除 <service android:process="..."> 和相关 BroadcastReceiver。

收益:§02 案例节省 60MB + 主进程被杀率 22%→3%。

边界:业务方可能依赖"保活"假设,需 review 并提供 WorkManager 替代方案。

# 13.4 评估每个 ContentProvider 是否真需独立进程

机理:很多 SDK 用 android:process=":xxx" 默认拆,但实际不必要。

代码:

<!-- 反例:默认拆,但实际 SDK 在主进程也工作 -->
<provider android:name="..." android:process=":sdk" />

<!-- 正例:合并到主进程 -->
<provider android:name="..." />
1
2
3
4
5

收益:每删一个进程节省 30-50MB。

边界:需测试 SDK 在主进程的兼容性。

# 13.5 进程数量收敛检查清单

  • [ ] 列出所有 :xxx 进程清单
  • [ ] 每个进程评估"真实工作时长占比"
  • [ ] 删除占比 < 1% 的进程(合并到主)
  • [ ] 删除"为了保活"的所有进程
  • [ ] 仅保留"风险隔离"或"内存隔离"必要的进程

探索性思考:为什么"删进程"是工程上最有效但最难执行的优化?因为删进程涉及架构变更——架构师本能抵抗。好的工程文化要让"删代码"成为荣誉而非耻辱。删一个无用进程比加一个新功能更有价值。

▶▶ 回扣 §02 案例:方法派 Day 4 第 1 层"删除 3 个非必要进程"是案例中最大的杠杆——单步收益 PSS -47%,远超后续所有优化之和。找到"最大杠杆"是优化的关键。


# 14.治理二层 IPC

核心命题:让 IPC 不再是瓶颈。让通信少、让通信批、让通信用对方式。

# 14.1 IPC 批量化

机理:§17.4 实验循环 100 次 vs 批量 1 次差 60×。

代码:

// 反例
configs.forEach { key ->
    val value = remoteService.get(key)  // 100 次跨进程
    ...
}

// 正例
val map = remoteService.getBatch(configs)  // 1 次
1
2
3
4
5
6
7
8

收益:循环场景从 500ms 阻塞降到 8ms。

边界:批量 API 设计要避免单次过大(> 100KB 走共享内存)。

# 14.2 主进程本地缓存 + Push 失效

机理:跨进程数据"启动加载一次 + 变更时 push 失效"是最高效模式。

代码:

class ConfigCache {
    private val cache = ConcurrentHashMap<String, String>()
    fun init() {
        cache.putAll(remoteService.getAll())  // 启动一次
    }
    fun onConfigChanged(key: String, value: String) {
        cache[key] = value  // 远端变更时通过 broadcast 通知
    }
    fun get(key: String) = cache[key]  // 零 IPC
}
1
2
3
4
5
6
7
8
9
10

收益:日常读 0 IPC;变更时一次 push。

边界:内存换性能,仅适合数据量不大(< 10MB)的场景。

# 14.3 大数据用共享内存

机理:§17.2 实验1MB Binder < 1000 op/s 实际不可用。

代码(Android SharedMemory API 27+):

SharedMemory shm = SharedMemory.create("frame", frameSize);
ByteBuffer buffer = shm.mapReadWrite();
remoteService.submitFrame(shm);  // 通过 Binder 传递句柄
1
2
3

收益:图片/视频帧/大 JSON 传输延迟 -90%。

边界:首次建立 mmap 有 1-2ms 开销;少次大数据可能不如直接 IPC。

# 14.4 异步化 IPC + Future 模式

机理:主线程同步等远程返回 = ANR 风险。

代码:

// oneway 方法不阻塞调用方
interface IRemoteService {
    oneway void doAsync(in Request r);
}
1
2
3
4

收益:主线程永不被 IPC 阻塞。

边界:oneway 不能有返回值;需 RemoteCallback 异步回调。

# 14.5 IPC 治理决策表

数据量 调用频次 推荐方式
< 1KB < 10/s 直接 IPC
< 1KB > 100/s 批量化 / 缓存
1KB-100KB < 10/s 直接 IPC
1KB-100KB > 10/s 批量化
> 100KB 任意 共享内存
> 1MB 任意 必须共享内存

探索性思考:为什么"IPC 频次"比"IPC 单次开销"更重要?因为单次 4μs 的开销看似可忽略,但 100 次/s × 86400s = 864 万次/天,累积成本巨大。性能优化经常是"积少成多" —— 单点不重要,总量决定成败。

▶▶ 回扣 §02 案例:主→Push 进程每秒 35 次 IPC 心跳——单次 4μs 看不出问题,每天累积 300 万次确实是负担。删除 Push 进程后这 300 万次/天直接消失。


# 15.治理三层隔离

核心命题:不是所有"为了稳定"的拆都合理。只拆"真值得"的。

# 15.1 WebView 强制进程外(必要的拆)

机理:H5 内容 JS 崩溃 / 内存泄漏会直接拖垮主进程。Android WebView 默认在主进程,必须显式启用多进程。

代码:

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        WebView.setDataDirectorySuffix("multi")
        // 多进程 WebView 通过 WebView 5.0+ 自动启用(API 28+)
    }
}
1
2
3
4
5
6
7

收益:§18.1 案例主进程崩溃率 0.18%→0.04%。

边界:WebView 进程也占 60-80MB;H5 业务少时不必拆。

# 15.2 高风险第三方 SDK 进程隔离

机理:闭源 SDK(如某些视频解码 / RTC / 推流)质量不可控,崩溃会拖垮主进程。

代码:

<service android:name=".RtcService"
    android:process=":rtc" />
1
2

收益:第三方崩溃不再影响主进程。

边界:SDK 必须支持跨进程调用;增加 IPC 复杂度。

# 15.3 大对象处理进程隔离

机理:图像识别 / 视频解码 / 大文件处理瞬间内存可能 200MB+,独立进程被杀也不影响主进程。

代码:见 §15.2。

收益:主进程内存稳定,OOM 风险隔离。

边界:处理结果通过共享内存返回;启动开销需评估。

# 15.4 ProcessExitReason 监控

机理:Android 11+ getHistoricalProcessExitReasons 给出进程被杀原因。

代码:

val am = context.getSystemService(ActivityManager::class.java)
am.getHistoricalProcessExitReasons(null, 0, 100)
    .forEach { 
        upload(it.reason, it.processName, it.pss, it.timestamp) 
    }
1
2
3
4
5

收益:分类统计被杀原因(LMK/ANR/Force Stop/JNI Crash),针对性优化。

边界:仅 Android 11+;部分 OEM 实现不全。

# 15.5 隔离的判断标准

值得拆的标准:

  • ✅ 代码质量不可控(闭源 SDK)
  • ✅ 内存占用瞬间 200MB+
  • ✅ 崩溃率 > 0.5%(拖垮主进程概率大)
  • ✅ 业务必要(如 Web 内容)

不值得拆的标准:

  • ❌ 仅"为了保活"
  • ❌ 业务正常(崩溃率 < 0.05%)
  • ❌ 内存占用稳定且小
  • ❌ "感觉应该拆"(无数据支持)

探索性思考:为什么"隔离"不应该是默认决策?因为隔离的代价是"立刻可见"(内存、IPC),收益是"事件性"(异常时才出现)。如果异常发生概率极低,隔离的期望收益就低于代价。默认单进程,只在数据证明必要时才拆 —— 这是工程上的"奥卡姆剃刀"。

▶▶ 回扣 §02 案例:方法派保留 WebView 进程,因为 H5 业务多崩溃概率高;删除 Push/守护/拉活进程,因为它们的"隔离收益"是零(无 H5 风险,仅为保活)。分类施治才是正解。


# 16.治理四层重启

核心命题:放弃保活,拥抱快速重启。这是范式转移。

# 16.1 关键状态持久化

机理:被杀时立即持久化(最后页面/滚动位置/输入草稿/登录态/购物车等)。

代码:

class StateRecoveryManager(context: Context) {
    private val prefs = context.getSharedPreferences("recovery", MODE_PRIVATE)
    
    fun saveState(page: String, scrollY: Int, draft: String?) {
        prefs.edit().apply {
            putString("last_page", page)
            putInt("scroll_y", scrollY)
            putString("draft", draft)
            putLong("save_ts", System.currentTimeMillis())
            apply()  // 异步,不阻塞
        }
    }
    
    fun restoreOnStart(): RestoreState? {
        val saveTs = prefs.getLong("save_ts", 0)
        if (System.currentTimeMillis() - saveTs > 24*3600*1000) return null
        return RestoreState(/* ... */)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

收益:§17.5 实验用户回到状态时长 4.5s→0.95s。

边界:状态版本兼容(旧状态 + 新代码);敏感信息加密。

# 16.2 启动期优先恢复状态

机理:启动序列改为"先渲染上次页面骨架 → 恢复滚动位置 → 再异步加载数据"。

代码:见 卷四·01 冷启动篇分级初始化策略。

收益:感知冷启时间从 3s 降到 < 1s。

边界:复杂业务需逐场景设计;不可滥用占位骨架。

# 16.3 合规后台任务用 WorkManager

机理:替代守护进程,系统调度,合规可靠。

代码:

val work = PeriodicWorkRequestBuilder<MyWorker>(15, TimeUnit.MINUTES)
    .setConstraints(Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build())
    .build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "sync", 
    ExistingPeriodicWorkPolicy.KEEP, 
    work
)
1
2
3
4
5
6
7
8
9
10

收益:合规且电池友好;不被系统打压。

边界:调度延迟 10s-15min(视约束),实时性差任务不适用。

# 16.4 长连接业务用前台 Service

机理:§17.3 实验唯一有效保活手段。

代码:

class ChatForegroundService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val notification = NotificationCompat.Builder(this, channelId)
            .setContentTitle("聊天已连接")
            .setSmallIcon(R.drawable.ic_chat)
            .build()
        startForeground(NOTIFICATION_ID, notification)
        return START_STICKY
    }
}
1
2
3
4
5
6
7
8
9
10

收益:A13 8h 存活率 75%。

边界:必须有用户可见的通知;滥用会被举报"流氓应用"。

# 16.5 ROI 排序

ROI 优化项 收益 成本 风险 对应章节
极高 评估并删除非必要子进程 内存 -30-50% 1-2 周 中 §13.1-13.4
极高 大数据 IPC 改共享内存 IPC 延迟 -90% 1 周 低 §14.3
极高 关键状态持久化 + 快速重启 体验 4.5s→1s 2-3 周 中 §16.1-16.2
高 IPC 批量化 + 本地缓存 IPC 频次 -80% 1-2 周 低 §14.1-14.2
高 放弃暗保活 + WorkManager 系统评分提升 1-2 周 中 §16.3
高 Push 进程合并到主 节省 50-80MB 1 周 中 §13.2
中 WebView 进程隔离 主进程崩溃 -75% 几天 低 §15.1
中 ProcessExitReason 监控 长期防退化 几天 低 §15.4
中 异步 oneway IPC 主线程不被阻塞 1 周 低 §14.4
中 前台 Service(长连接) 长连接稳定 1 周 中 §16.4

# 16.6 避免反向收益

  • 过度拆进程:每个业务都独立进程,内存翻 N 倍。
  • 死磕保活:A11+ 无效,投入精力对抗系统,最终被卸载。
  • 小数据用共享内存:建立 mmap 有开销,反而比 Binder 慢。
  • 循环跨进程查询:累积可达秒级,制造 ANR 风险。
  • 加强保活治被杀:§02 案例第 1 周翻车的根因。

探索性思考:为什么"放弃保活"这么难?因为产品经理和老板"想要应用一直活着"——这是直觉但反工程现实。好的工程师要会"教育产品" —— 用数据告诉他们"暗保活不仅无效,还伤体验"。说服比写代码更难。

▶▶ 回扣 §02 案例:方法派 Day 4 第 4 层"快速重启 + 状态恢复"是范式转换的关键——把"保活成功率"指标换成"重启 + 恢复时长"指标。指标变了,思维就变了。


# 17.求证实验 ⭐

本节是"为什么这些优化生效"的实证基础。每个实验严格遵循"6 步求证法"。

# 17.1 实验一:进程启动代价

猜想:进程启动几乎瞬时。

假设:Android Zygote fork(共享父 VM)~200ms;iOS exec(每次重启 dyld)~250ms;纯 Linux fork ~10ms。

执行:

平台 测试场景 启动时长(中位)
Android Zygote fork ContentProvider 跨进程 230 ms
Android no-Zygote(手动 spawn) 命令行 800 ms
iOS App Extension 触发 sharing extension 280 ms
iOS posix_spawn 命令行 /usr/bin/true 50 ms
Linux fork + exec /bin/true 8 ms
Web 新 Tab window.open 启动新进程 220 ms

验证:

  • Android 与公式预测 ~200ms 一致。
  • iOS Extension 比公式略高(含 XPC 握手)。

思考:

  • 应用级进程启动开销 200-300ms,远高于线程创建(μs 级)。
  • 子进程要保持常驻,不要频繁拉起 / 销毁。
  • 一次性任务用线程,长期任务才用进程。

# 17.2 实验二:IPC 吞吐量

猜想:IPC 吞吐与数据大小无关。

假设:小数据吞吐被切换开销主导;大数据吞吐受序列化 + 拷贝主导。

执行:

数据大小 Android Binder iOS XPC Web postMessage
100B 220K op/s 180K op/s 90K op/s
1KB 180K op/s 150K op/s 80K op/s
10KB 65K op/s 55K op/s 35K op/s
100KB 9K op/s 7K op/s 5K op/s
1MB 950 op/s 700 op/s 500 op/s

验证:

  • 小数据被调用开销主导,大数据被拷贝主导。
  • 1MB 数据已经接近不可用。

思考:

  • IPC 吞吐量随数据大小急剧下降。
  • 100B 数据 200K/s 可用;100KB 数据 < 10K/s 需要谨慎;1MB+ 必须用共享内存。
  • 频繁小数据交互直接 IPC;大数据传输(图片 / 视频帧)必须共享内存。

# 17.3 实验三:保活策略效果

猜想:保活仍然有效。

假设:Android 8.0+ 后系统强力打压;只有前台 Service 仍有效。

执行:

保活手段 A7 30min A11 30min A13 30min A13 8h
无 35% 15% 10% 0%
双进程互拉 70% 25% 18% 2%
JobScheduler 60% 45% 40% 25%
前台 Service 95% 88% 85% 75%

验证:

  • 双进程互拉在 A11+ 几乎失效。
  • JobScheduler 是合规但效果有限。
  • 只有前台 Service(带通知)才能稳定保活。

思考:

  • Android 11+ 后"暗保活"几乎全部失效。
  • 投入做"暗保活"是低 ROI 工作,应放弃。
  • 转而做"快速重启 + 状态恢复"。

▶▶ 回扣 §02 案例:经验派第 1 周"加强双进程互拉保活"是把"硬抗系统"变现为线上事故的真实样本。

# 17.4 实验四:CP 风暴

猜想:循环 IPC 与批量 IPC 差异不明显。

假设:每次 ContentProvider 查询 ~5ms;100 次 = 500ms 主线程阻塞;批量一次 ~8ms。

执行:

实现 总耗时 子进程被拉起次数
A 循环 100 次 480 ms 1 次
极端:A + 每次后子进程退出 22,000 ms 100 次
B 批量一次 8 ms 1 次
C 本地缓存(启动加载) 0.05 ms 0 次

验证:

  • A 循环 100 次主线程阻塞 480ms 直接 ANR 临界。
  • 子进程反复唤醒时极端 22 秒。
  • B 批量比 A 快 60×;C 本地缓存比 B 快 160×。

思考:

  • 跨进程 ContentProvider 严禁循环调用。
  • 必须批量化或本地缓存。
  • "看起来 5ms 一次的调用"在循环中可累积到秒级。

# 17.5 实验五:快速重启 vs 暗保活

猜想:暗保活体验更好。

假设:暗保活成功率 < 40%,且拉起仍需冷启;快速重启 100% 成功,且 < 800ms 完成。

执行:

离开时长 A 暗保活存活率 A 用户回到状态时长 B 重启时长 B 用户回到状态时长 A 评分 B 评分
30 min 38% 2.5s(命中)/ 4.2s(冷启) 100% 0.9s 3.2 4.6
2 h 18% 4.5s 100% 0.9s 2.8 4.5
8 h 5% 4.8s 100% 0.95s 2.4 4.5

验证:

  • B 实测平均回到状态的时长 < 1s。
  • A 在长时间离开后存活率几乎为零。
  • 用户主观分 B 显著高于 A。

思考:

  • 放弃保活 + 投资快速重启是更高 ROI 的路径:100% 成功率 vs 5-38% 存活率。
  • 关键状态(最后页面 / 滚动位置 / 输入草稿 / 登录态)持久化到磁盘。
  • 启动期优先恢复状态。

# 17.6 五大实验启示

   进程启动代价(200-300ms) → 不要频繁拉起子进程        ─┐
   IPC 吞吐量             → 大数据必用共享内存             │
   保活几乎失效           → 转向"快速重启 + 恢复"          ├─▶ 多进程 = 重资源,每开必算账
   ContentProvider 风暴   → 严禁循环 IPC,必须批量化        │
   快速重启 vs 暗保活     → 100% 成功率 + <1s 体验          ─┘
1
2
3
4
5

统一启示:

  • 多进程是"重武器":每开一个进程都要算清成本收益。
  • 顺应系统而非对抗:现代 OS 都在打压持久后台。
  • 快速重启 > 永不被杀:投资"被杀后的恢复体验" ROI 高得多。
  • IPC 频次 > IPC 单次开销:单次便宜的接口,循环调用一样杀人。
  • 大数据必用共享内存:Binder/XPC 在 1MB+ 数据下不可用。

▶▶ 回扣 §02 案例:方法派 8 天闭环每一步都对应本节实验。实验是优化前的"必经之路"。


# 18.实战案例

# 18.1 跨端同构案例:WebView 进程隔离

背景:某社交应用主进程因加载 Web 内容偶发崩溃。

现象:

  • Android:第三方网页 JS 引起 WebView 崩溃,导致主进程崩溃
  • iOS:WKWebView 已经进程外(系统级),无问题
  • Web:iframe 默认进程外(部分浏览器),无问题

根因:Android WebView 默认在主进程渲染(除非显式启用多进程模式)。

治理:

  • Android:启用 WebView 多进程(WebView.setDataDirectorySuffix)
  • iOS:保持 WKWebView(已经默认进程外)
  • Web:用户层不用关心

效果:

平台 优化前主进程崩溃率(含 Web 原因) 优化后
Android 0.18% 0.04%
iOS 0.05% 0.05%(无变化)
Web N/A N/A

核心洞察:跨端原则 = 风险代码必须进程隔离。Android 需要显式启用,iOS / Web 默认提供。

# 18.2 平台特异案例:iOS Extension 内存超限

背景:某 App 的 Share Extension 在分享大图时崩溃。

根因:

  • iOS Extension 内存限制 30-50MB
  • 用户分享 4K 图片时解码占用 80MB+
  • 系统直接杀掉 Extension

治理:

  • 大图分享前先降采样到 < 2K
  • 用 mmap 读图避免一次性载入
  • 关键状态用 App Group 与主 App 共享

效果:Share Extension 崩溃率 8% → 0.3%。

洞察:iOS Extension 是"小内存 + 短生命周期"环境 —— 工程师不能用主 App 的内存假设来设计 Extension。

# 18.3 反例案例:暗保活引发的恶性循环

背景:某 App 投入大量精力做"双进程互拉 + JobScheduler + 系统服务绑定"组合保活。

结果:

  • Android 11+ 后系统识别"贪婪应用",反向打压
  • 主进程被杀率从 5% 升到 25%
  • 用户体验更差,差评激增
  • 浪费了 3 个月研发时间

修复:

  • 全部撤销保活手段
  • 投资"快速重启 + 状态恢复"
  • 关键长连接业务用前台 Service(带通知)

效果:

  • 主进程被杀率 25% → 4%(系统不再打压)
  • 用户感知"启动快"(< 1s)

洞察:对抗系统从未赢过——iOS / Android 的进化方向都是"限制后台贪婪",应用应顺应而非对抗。


# 19.防劣化体系

# 19.1 三道防线总览

   ┌────────────┐     ┌────────────┐     ┌────────────┐
   │ 编码期 Lint │  →  │ CI 卡口     │  →  │ 线上 SLO    │
   │ IDE 即时提示│     │ Macrobench  │     │ 监控告警    │
   └────────────┘     └────────────┘     └────────────┘
1
2
3
4

# 19.2 编码期 Lint

自定义规则:

  • 新增 <service android:process=":xxx"> → 警告(必须 review)
  • 循环跨进程调用 contentResolver.query → 警告
  • 主线程同步等待 IPC → 错误
  • 大数据(> 100KB)用 Binder → 警告(建议共享内存)
  • 守护进程相关代码 → 警告(A11+ 失效)
  • 未声明 ProcessExitReason 监听 → 警告

# 19.3 CI 卡口

性能基线测试:

@Test
fun processCountBenchmark() = benchmarkRule.measureRepeated(
    metrics = listOf(MemoryUsageMetric(Mode.Last)),
    iterations = 5
) {
    startActivityAndWait()
    repeat(20) { exerciseFeature() }
}
1
2
3
4
5
6
7
8

卡口规则:

  • 进程数增加 → 阻断 PR(需架构师 review)
  • 常驻 PSS 退化 ≥ 10% → 阻断
  • IPC 延迟退化 ≥ 20% → 警告
  • 启动期进程拉起次数增加 → 警告

# 19.4 线上 SLO

指标 目标 告警阈值
应用进程数稳态 < 3 > 5
主进程 PSS < 200MB > 350MB
主进程被杀率 < 5% > 10%
IPC 失败率 < 0.1% > 1%
进程冷启时长 P95 < 800ms > 1.5s
推送到达率 > 95% < 90%

# 19.5 文化建设

  • 进程预算:新模块申请独立进程必须有"为什么"(不能默认)
  • 进程 Code Review:进程相关 PR 必有架构师 review
  • 进程 OKR:进程数稳态进 OKR

探索性思考:为什么"进程治理"特别需要架构师 review?因为进程决策具有长期效应 —— 加一个进程容易,删一个进程难(业务依赖建立后)。预防胜于治疗 —— review 阶段拦下"轻易加进程"的 PR,远比上线后清理省力。


# 20.跨平台速查

# 20.1 工具速查

平台 进程清单 IPC 采集 生命周期
Android ActivityManager / ps Perfetto Binder getHistoricalProcessExitReasons
iOS sysctl Instruments XPC terminationReason
Web chrome://process-internals Performance Panel (无标准)
Linux ps -ef strace -e ipc (cgroup logs)

# 20.2 关键 API 速查

目的 Android iOS Web
启用子进程 <service android:process=":xxx"> App Extension new Worker
同步 IPC AIDL NSXPCConnection postMessage
异步 IPC oneway AIDL XPC handler postMessage
共享内存 SharedMemory(API 27+) mmap + shm_open SharedArrayBuffer
进程退出原因 getHistoricalProcessExitReasons (无) (无)
后台调度 WorkManager BGTask Service Worker
长连接保活 startForeground VoIP / location (无)
WebView 进程外 setDataDirectorySuffix WKWebView 默认 (默认)

# 20.3 各平台优化清单

Android:

  • [ ] 进程清单评估,删除非必要进程
  • [ ] WebView 启用多进程(H5 业务多)
  • [ ] Push 改 FCM/厂商推送 + 主进程接收
  • [ ] 删除守护/拉活进程
  • [ ] IPC 批量化,主进程缓存
  • [ ] 大数据用 SharedMemory
  • [ ] 关键状态持久化 + 快速重启
  • [ ] WorkManager 替代守护
  • [ ] ProcessExitReason 上报
  • [ ] Lint 拦截新增进程

iOS:

  • [ ] 减少 dylib 数量
  • [ ] 减少 +load 方法
  • [ ] App Group + UserDefaults 共享
  • [ ] Extension 内存严控
  • [ ] BGTask 替代保活
  • [ ] WKWebView(自动进程外)

Web:

  • [ ] Site Isolation 利用
  • [ ] Web Worker 处理 CPU 密集
  • [ ] SharedArrayBuffer + Atomics(高性能场景)
  • [ ] Service Worker 离线缓存

# 21.总结与延伸

# 21.1 五条核心原则

  1. 进程是重资源:每开一个进程都要算清成本收益。
  2. 顺应系统而非对抗:现代 OS 都在打压持久后台,硬抗代价大。
  3. 快速重启 > 永不被杀:投资"被杀后的恢复体验",比投资"保活"ROI 高得多。
  4. IPC 频次 > IPC 单次开销:单次便宜的接口,循环调用一样杀人。
  5. 大数据必用共享内存:Binder/XPC 在 1MB+ 数据下不可用。

# 21.2 五个常见误区

误区 真相
"拆进程 = 稳定性提升" 错。除非是真正的高风险代码,拆进程只增加成本
"保活做得好就不被杀" 错。Android 11+ 暗保活几乎全失效
"Binder 跟函数调用差不多" 错。3 个量级差距(μs vs ns)
"iOS 没进程问题" 错。Extension 内存限制是新挑战
"SharedMemory 总比 Binder 快" 错。建立 mmap 有开销,少次大数据用 Binder 更快

# 21.3 一句话总结

进程是"隔离单元,也是性能边界"。多进程优化的核心法则:删除非必要进程(最大杠杆)+ IPC 批量化与共享内存(让通信不再瓶颈)+ 风险代码精准隔离(值得拆才拆)+ 放弃保活拥抱快速重启(顺应而非对抗系统)。Android 11+ 时代,"保活"已经是反模式,"快速重启 + 状态恢复"才是正解。

# 21.4 延伸阅读

  • 卷二·04 线程模型与调度优化:进程 vs 线程的对比
  • 卷二·03 OOM 异常与低内存治理:多进程是 OOM 隔离重要手段
  • 卷四·01 App 冷启动优化:进程启动开销是冷启大头
  • 卷三·04 ANR 监控与治理:跨进程同步 IPC 是 ANR 常见原因
  • 卷四·05 功耗与电量优化:保活伤电池

下一篇预告:卷二·06 IO 与存储性能 —— 让"持久化"不成为性能瓶颈。

上次更新: 2026/06/07, 10:26:12
线程模型调度优化
IO与存储性能

← 线程模型调度优化 IO与存储性能→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式