2. Linux 内核休眠框架:四种模式的原理与区别
做嵌入式电源管理,绕不开 Linux 的休眠框架。很多刚入行的朋友问我:「不就是个休眠吗,关掉屏幕不就行了?」
嗯,真没那么简单。Linux 内核提供了四种休眠模式,每种模式的功耗、唤醒延迟、实现原理都完全不同。
我个人习惯把这四种模式看作一个「深度阶梯」——从浅睡到深睡,再到彻底关机。
2.1 四种模式总览
先看一张总览图,帮你建立整体认知:
2.2 suspend-to-idle(冻结)
这是最浅的休眠模式。说白了,就是把用户空间的进程全部冻结,内核线程继续跑。
CPU 并没有真正进入深度睡眠,只是空闲下来。
工作原理:
- 系统调用
pm_suspend(PM_SUSPEND_TO_IDLE) - 冻结所有用户空间进程(freeze_processes)
- CPU 进入 idle 循环,等待中断唤醒
- 唤醒源:任何中断(按键、网络包、定时器)
我的经验: 在平板电脑项目中,我习惯用 suspend-to-idle 做「假待机」。屏幕关了,但 Wi-Fi 保持连接,消息能秒到。唤醒延迟只有几十毫秒,用户体验很好。
2.3 standby(待机)
standby 比 suspend-to-idle 深一步。它会把 CPU 主频降下来,甚至让部分 CPU 核心离线。
但内存仍然保持正常供电,没有进入自刷新模式。
关键特征:
- CPU 进入更深度的空闲状态(WFI 或 WFE)
- 部分外设时钟被关闭
- 内存控制器仍在工作
- 唤醒延迟:毫秒级
注意: 很多 ARM 平台的 SoC 并不真正支持 standby 模式。我在调试 RK3588 时发现,它的 standby 和 suspend-to-idle 行为几乎一样。你最好查一下芯片手册,别被内核选项骗了。
2.4 suspend-to-RAM(STR,挂起到内存)
这是嵌入式产品中最常用的深度休眠模式。
系统会把所有设备的状态保存好,然后让内存进入自刷新模式,切断 CPU 和大部分外设的电源。
核心流程:
1. 用户空间冻结
2. 设备驱动 suspend 回调
3. 关闭非唤醒中断
4. 关闭 CPU 二级缓存
5. 内存控制器进入自刷新
6. CPU 进入 WFI,等待唤醒事件
7. 唤醒后反向恢复
你想想看,为什么叫「挂起到 RAM」?因为系统状态全部保存在 RAM 里,RAM 是唯一保持供电的部件。
唤醒时直接从 WFI 处恢复执行,速度很快。
关键参数: 唤醒延迟通常在 100ms ~ 500ms 之间。我在智能门锁项目里,把 STR 唤醒优化到了 180ms,用户按指纹后几乎感觉不到等待。
2.5 suspend-to-disk(STD,休眠到磁盘)
这是最深度的休眠,也叫 hibernate。
系统会把整个内存镜像写入磁盘(或 flash),然后完全断电。下次开机时,从磁盘加载镜像,恢复到休眠前的状态。
实现方式:
- 内核需要 swap 分区或 swap 文件
- 镜像大小 = 内存大小 + 元数据
- 支持压缩(LZO、LZ4)
- 支持加密(可选)
我曾经踩过的坑: 在 NAND flash 上做 hibernate,写入速度只有几 MB/s,8GB 内存的镜像要写几分钟。而且 NAND 的擦写寿命有限,频繁 hibernate 会加速 flash 老化。后来我改用 squashfs + overlayfs 的方案,才解决了这个问题。
2.6 四种模式对比表
| 特性 | suspend-to-idle | standby | suspend-to-RAM | suspend-to-disk |
|---|---|---|---|---|
| 功耗 | 较高(CPU 仍在跑) | 中等 | 低(仅 RAM 供电) | 零(完全断电) |
| 唤醒延迟 | 10~50ms | 50~200ms | 100~500ms | 5~30s |
| 内存状态 | 正常 | 正常 | 自刷新 | 断电 |
| CPU 状态 | 空闲 | 深度空闲 | 断电 | 断电 |
| 外设状态 | 部分关闭 | 大部分关闭 | 全部关闭 | 全部关闭 |
| 适用场景 | 需要快速响应 | 轻度省电 | 深度省电 | 长时间关机 |
2.7 如何选择?
我个人总结了一个简单的选择原则:
- 需要保持网络连接? → suspend-to-idle
- 用户可能随时唤醒? → suspend-to-RAM
- 电池快没电了? → suspend-to-disk
- 芯片不支持 STR? → standby 或 suspend-to-idle
小技巧: 很多产品会做「混合休眠」——先尝试 STR,如果电池电量低于阈值,自动转为 hibernate。我在车载项目中就用过这个策略,效果很好。
2.8 内核配置与调试
查看当前系统支持的休眠模式:
cat /sys/power/state
# 输出示例:freeze mem disk
手动触发休眠:
echo freeze > /sys/power/state # suspend-to-idle
echo mem > /sys/power/state # suspend-to-RAM
echo disk > /sys/power/state # suspend-to-disk
查看休眠统计信息:
cat /sys/power/suspend_stats
# 可以看到成功/失败的次数和最后失败原因
调试建议: 我习惯在调试阶段打开内核的 PM 调试日志:
这样可以看到每个设备 suspend/resume 的耗时,方便定位瓶颈。
echo 1 > /sys/power/pm_debug_messages这样可以看到每个设备 suspend/resume 的耗时,方便定位瓶颈。
嗯,四种模式讲完了。记住一个核心原则:休眠越深,功耗越低,但唤醒越慢。实际项目中,没有最好的模式,只有最适合的模式。