AOSP CachedAppOptimizer中的冻结和内存压缩功能
AOSP CachedAppOptimizer:应用进程长期处于 Cached 状态的内存压缩和冻结优化管控
冻结和内存压缩两个功能独立触发,可以单独触发也可以组合触发,默认顺序:先压缩,后冻结
public class OomAdjuster {
protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,{
...
if (state.getCurAdj() != state.getSetAdj()) {
//内存压缩
mCachedAppOptimizer.onOomAdjustChanged(state.getSetAdj(), state.getCurAdj(), app);
}
...
updateAppFreezeStateLSP(app, oomAdjReson, false);
...
}
void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason,
...
if (state.getCurAdj() >= FREEZER_CUTOFF_ADJ && !opt.isFreezeExempt() && !opt.shouldNotFreeze()) {
// 异步冻结
freezeAppAsyncLSP(app); // 调用 mCachedAppOptimizer.freezeProcess
}
...
}
public final class CachedAppOptimizer {
@GuardedBy({"mService", "mProcLock"})
void onOomAdjustChanged(int oldAdj, int newAdj, ProcessRecord app) {
if (useCompaction()) {
// Cancel any currently executing compactions
// if the process moved out of cached state
if (newAdj < oldAdj && newAdj < ProcessList.CACHED_APP_MIN_ADJ) {
cancelCompactionForProcess(app, CancelCompactReason.OOM_IMPROVEMENT);
}
}
}
void onProcessFrozen(ProcessRecord frozenProc) {
if (useCompaction()) {
synchronized (mProcLock) {
compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
}
}
frozenProc.onProcessFrozen();
}
}
行为模式 | 触发条件 | 资源压力/策略 |
只冻结,不压缩 | -state.getCurAdj() >= FREEZER_CUTOFF_ADJ -!opt.isFrozen() -!opt.shouldNotFreeze() | - 内存充足但需省电 - 进程优先级未触发压缩阈值 newAdj ≥ CACHED_APP_MIN_ADJ |
同时冻结+压缩 | -oom_adj ≥ CACHED_APP_MIN_ADJ - 进程未被取消压缩(!mPendingCompactionProcesses.contains(app) | - 内存碎片化严重(compact_full_rss_throttle_kb) - 低电量模式 |
只压缩,不冻结 | -oom_adj ≥ CACHED_APP_MIN_ADJ -opt.isFreezeExempt()或 state.getCurAdj() < FREEZER_CUTOFF_ADJ | - CPU负载低 - 进程标记为不可冻结(如persistent) |
不冻结也不压缩 | -oom_adj < CACHED_APP_MIN_ADJ - 或opt.shouldNotFreeze() - 或压缩被取消(CancelCompactReason) |
冻结(Freezer)策略与压缩交互
冻结(Freezer)和压缩(Compaction)的执行顺序是明确且不可随意调换的。默认顺序:先压缩,后冻结,冻结依赖压缩完成
冻结会将进程的内存页标记为不可移动(PG_dontdump),若先冻结再压缩,内核会跳过冻结进程的内存页,导致压缩失效。
场景 | 冻结状态 | 压缩状态 | 说明 |
进程刚进入缓存 | ❌ 未冻结 | ✅ 可压缩 | 优先触发FULL压缩,再根据资源压力决定是否冻结。 |
进程长期缓存 | ✅ 已冻结 | ❌ 不压缩 | 冻结后内存页标记为不可移动(PG_dontdump),避免压缩开销。 |
进程解冻后 | ❌ 解冻 | ✅ 可压缩 | 若仍满足缓存条件,可能触发新一轮压缩(需冷却时间)。 |