2. Linux 内核休眠框架:四种模式的原理与区别

做嵌入式电源管理,绕不开 Linux 的休眠框架。很多刚入行的朋友问我:「不就是个休眠吗,关掉屏幕不就行了?」
嗯,真没那么简单。Linux 内核提供了四种休眠模式,每种模式的功耗、唤醒延迟、实现原理都完全不同。
我个人习惯把这四种模式看作一个「深度阶梯」——从浅睡到深睡,再到彻底关机。

2.1 四种模式总览

先看一张总览图,帮你建立整体认知:

Linux 内核四种休眠模式对比 Linux 内核四种休眠模式 suspend-to-idle 冻结用户空间 standby CPU 进入空闲 suspend-to-RAM 内存自刷新 suspend-to-disk 镜像写入磁盘 深度:浅 深度:↓ 深度:↓ 深度:深 功耗:低 功耗:中 功耗:高 功耗:最高 延迟:最快 延迟:快 延迟:慢 延迟:最慢 💡 关键规律: 休眠越深 → 功耗越低 → 唤醒延迟越大。实际项目中需要根据产品场景做取舍。

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 调试日志:
echo 1 > /sys/power/pm_debug_messages
这样可以看到每个设备 suspend/resume 的耗时,方便定位瓶颈。

嗯,四种模式讲完了。记住一个核心原则:休眠越深,功耗越低,但唤醒越慢。实际项目中,没有最好的模式,只有最适合的模式。