大家好,我是冯哥的缓存。上篇带大家搞清楚了 suspend 和 hibernate 的区别,还学会了用 journalctl 查日志定位问题。今天这篇全是动手修——swap 不够怎么办、NVIDIA 唤醒黑屏怎么解决、Wi-Fi 唤醒断线怎么搞。
回顾:诊断结果
先对照上篇的诊断流程,确认你的问题属于哪一种:
| | |
|---|
sudo systemctl hibernate | | |
cat /sys/power/mem_sleep | | |
| | |
| | |
| | |
| | |
| | |
一、swap 不足怎么办——swapfile 补救方案
S4 休眠需要 swap ≥ 内存大小。如果你装系统时 swap 分小了(甚至没有),不用重装系统,用 swapfile 补救。
方案A:新增 swapfile(不破坏现有分区)
# 1. 查看当前 swap 和内存
free -h
swapon --show
# 2. 创建一个 swapfile(假设要加 8GB)
sudo fallocate -l 8G /swapfile
# 如果 fallocate 不支持(某些文件系统),用 dd:
# sudo dd if=/dev/zero of=/swapfile bs=1M count=8192 status=progress
# 3. 设置权限(必须!否则不安全)
sudochmod 600 /swapfile
# 4. 格式化为 swap
sudo mkswap /swapfile
# 5. 启用
sudo swapon /swapfile
# 6. 验证
free -h
方案B:写入 fstab 永久生效
# 备份 fstab
sudocp /etc/fstab /etc/fstab.bak
# 追加 swapfile 条目
echo'/swapfile none swap sw 0 0' | sudotee -a /etc/fstab
# 如果之前已经有旧的 swap 行,记得注释掉或删除,避免冲突。
# 验证 fstab 没有写错
sudo mount -a
方案C:如果之前已有 swap 分区,想扩容量
# 在修改 swap 配置前,先关闭所有 swap 设备。
sudo swapoff -a
# 创建更大的 swapfile(比如 16GB)
sudo fallocate -l 16G /swapfile
sudochmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 更新 fstab:找到旧的 swap 行,改成新的
# 编辑 /etc/fstab,注释掉旧 swap 分区行,
# 加上 /swapfile none swap sw 0 0
休眠还需要内核参数
swap 配好之后,还要告诉内核休眠时把数据恢复到哪个分区:
# 1. 查看 swapfile 所在的根分区 UUID 和偏移量
sudo findmnt -no UUID -T /swapfile
filefrag -v /swapfile | grep -oP '^\s+\d+:\s+\K\d+' | head -1
# 如果该命令不输出数字,请手动查找 filefrag -v /swapfile 输出中第一列的数字(物理偏移量)。
# 输出示例:
# UUID: a1b2c3d4-...
# 偏移量: 12345678
# 2. 编辑 GRUB 配置
sudo nano /etc/default/grub
# 找到 GRUB_CMDLINE_LINUX_DEFAULT 这行,追加 resume 参数:
# GRUB_CMDLINE_LINUX_DEFAULT="quiet splash resume=UUID=a1b2c3d4-... resume_offset=12345678"
# 3. 更新 GRUB 并重启
sudo update-grub
sudo reboot
# 4. 重启后测试休眠
sudo systemctl hibernate
⚠️ 注意: 每次 fallocate 重新创建 swapfile 后,resume_offset 可能会变。所以swapfile 创建好之后尽量不要删了重建。如果需要调整大小,用 swapoff → 删旧文件 → fallocate 新大小 → mkswap → swapon → 重新查 filefrag 偏移量 → 更新 GRUB。
swap 容量建议
💡 提示: 如果你内存较大(32GB+)但几乎不用休眠,没必要搞一个 32GB 的 swapfile 占着硬盘。配个 8GB swap 应付日常就行,真需要休眠的时候再扩容。
二、切换 S3 deep 模式——内核参数实战
现代笔记本(特别是 Intel 12 代以后)BIOS 默认用 s2idle(浅度挂起)而不是传统的 S3 deep。s2idle 下 CPU 不完全断电,合盖一晚掉电 20%~30% 很常见。
检查当前模式
cat /sys/power/mem_sleep
| |
|---|
[s2idle] deep | |
s2idle [deep] | |
s2idle | |
临时切换到 deep 测试
# 临时切到 deep 模式(重启后失效)
echo deep | sudotee /sys/power/mem_sleep
# 如果提示 Permission denied 或写入失败,说明内核或 BIOS 不支持动态切换,跳过这一步。
# 测试挂起
sudo systemctl suspend
# 按电源键唤醒,看是否正常
如果唤醒正常,就把它永久化:
永久设置 deep 模式(GRUB 内核参数)
sudo nano /etc/default/grub
找到 GRUB_CMDLINE_LINUX_DEFAULT 这行,追加 mem_sleep_default=deep:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash mem_sleep_default=deep"
# 更新 GRUB
sudo update-grub
sudo reboot
# 重启后验证
cat /sys/power/mem_sleep
# 应显示 s2idle [deep]
🚨 警告: 部分笔记本(特别是某些 Dell/Lenovo 型号)的 BIOS 故意禁用了 S3 deep,强切 deep 后挂起可能彻底醒不过来(只能长按电源键强制关机)。如果 cat /sys/power/mem_sleep 输出里根本没有 deep 这个选项,说明硬件不支持,不要强切。
s2idle vs deep 对比
三、NVIDIA 休眠/挂起黑屏修复
NVIDIA 闭源驱动是 Linux 休眠问题的头号疑难杂症。
症状判断
| |
|---|
| 挂起后唤醒 → 黑屏,但系统活着(能盲打命令、SSH 能连) | |
| |
| |
修复方法一:添加内核参数(首选)
sudo nano /etc/default/grub
在 GRUB_CMDLINE_LINUX_DEFAULT 中追加以下参数:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nvidia-drm.modeset=1 nvidia.NVreg_PreserveVideoMemoryAllocations=1 nvidia.NVreg_TemporaryFilePath=/var/tmp"
参数解释:
| |
|---|
nvidia-drm.modeset=1 | 启用 DRM 内核模式设置,让 NVIDIA 更好地协同挂起/唤醒 |
nvidia.NVreg_PreserveVideoMemoryAllocations=1 | 关键参数——休眠时保留显存分配,唤醒后恢复。该参数需要 NVIDIA 驱动 470 或更高版本,用 nvidia-smi 确认版本。 |
nvidia.NVreg_TemporaryFilePath=/var/tmp | |
sudo update-grub
sudo reboot
修复方法二:启用 NVIDIA suspend/resume 服务
NVIDIA 驱动自带了一组 systemd 服务来管理挂起/休眠:
# 启用 NVIDIA 挂起恢复服务
sudo systemctl enable nvidia-suspend.service
sudo systemctl enable nvidia-hibernate.service
sudo systemctl enable nvidia-resume.service
验证服务状态:
systemctl status nvidia-suspend nvidia-hibernate nvidia-resume
💡 提示: 这三个服务的作用是:挂起前保存 NVIDIA 状态 → 唤醒后恢复。在 NVIDIA 驱动 525+ 版本中默认存在, 老版本NVIDIA 包默认没启用这些服务,需要手动创建 systemctl enable。
修复方法三:NVIDIA + Wayland 特殊处理
如果你用的是 Wayland + NVIDIA(Fedora 默认、Ubuntu 24.04 可选),还需要额外操作:
# 检查当前是 Xorg 还是 Wayland
echo$XDG_SESSION_TYPE
# 如果是 wayland,确保 modeset 已启用
cat /sys/module/nvidia_drm/parameters/modeset
# 应输出 Y
如果输出 N:
# 创建 modprobe 配置
echo"options nvidia-drm modeset=1" | sudotee /etc/modprobe.d/nvidia-drm.conf
# 如果重启后不生效,检查 /etc/modprobe.d/ 目录下是否有其他文件改变了加载顺序。
# 更新 initramfs
sudo update-initramfs -u
sudo reboot
NVIDIA 休眠黑屏排查流程
| | |
|---|
| nvidia-smi | |
| journalctl -b -1 | grep -i nvidia | |
| cat /sys/module/nvidia_drm/parameters/modeset | |
| systemctl is-enabled nvidia-suspend | |
| 从另一台电脑 SSH 进去跑 sudo systemctl suspend | |
四、GNOME 加休眠按钮
GNOME 默认不显示休眠选项,需要手动打开。
方法一:用快捷键或命令行触发
这才是最可靠的方法——不依赖 GNOME 菜单:
# 直接命令行休眠
sudo systemctl hibernate
# 或者设个快捷键:设置 → 键盘 → 快捷键 → 自定义快捷键
# 名称:休眠
# 命令:sudo systemctl hibernate
# 快捷键:比如 Ctrl+Alt+H
如果不想每次输 sudo:
# 允许当前用户免密码运行 systemctl hibernate
sudo visudo -f /etc/sudoers.d/hibernate
# 加一行:
# %sudo ALL=(ALL) NOPASSWD: /usr/bin/systemctl hibernate, /usr/bin/systemctl suspend, /usr/bin/systemctl hybrid-sleep
方法二:修改 logind 配置让合盖 = 休眠
sudo nano /etc/systemd/logind.conf
HandleLidSwitch=hibernate
HandleLidSwitchExternalPower=hibernate
sudo systemctl restart systemd-logind
这样合上盖子就走 S4 休眠而不是 S3 挂起。
GNOME 休眠按钮方案对比
| | | |
|---|
| | | |
| | | |
| | | |
| GNOME 扩展(Hibernate Status Button) | | | |
💡 提示: 我自己的习惯是改合盖 = 休眠 + 设个快捷键,双保险。快捷键备用,平时合盖就走。
五、Wi-Fi 唤醒断线修复
挂起唤醒后 Wi-Fi 断线是个常见问题,分几种情况:
情况A:唤醒后 Wi-Fi 完全消失(网卡没回来)
# 手动重新加载 Wi-Fi 驱动模块
sudo modprobe -r iwlwifi && sudo modprobe iwlwifi
# 或者
sudo modprobe -r mt7921e && sudo modprobe mt7921e
如果管用,可以写一个 systemd 服务自动执行:
sudo nano /etc/systemd/system/wifi-resume-fix.service
[Unit]
Description=Fix WiFi after resume
After=suspend.target hibernate.target hybrid-sleep.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/modprobe -r iwlwifi && /usr/sbin/modprobe iwlwifi
[Install]
WantedBy=suspend.target hibernate.target hybrid-sleep.target
sudo systemctl enable wifi-resume-fix.service
⚠️ 注意: 把 iwlwifi 换成你实际使用的驱动模块名(lsmod | grep -i wifi 查看)。modprobe -r 需要先卸载依赖模块,如果报错 module is in use,可以改用 rmmod 或重启后手动执行。
情况B:唤醒后能搜到 Wi-Fi 但连不上
# 重启 NetworkManager
sudo systemctl restart NetworkManager
同样可以做成自动服务:把上面服务文件里的 ExecStart 改成 ExecStart=/usr/bin/systemctl restart NetworkManager。
情况C:唤醒后自动连了 2.4GHz 而不是 5GHz
这是 NetworkManager 的行为问题,可以绑定频段:
# 查看你的 Wi-Fi 连接名
nmcli connection show
# 指定只用 5GHz(SSID 换成你的 Wi-Fi 名)
nmcli connection modify "你的WiFi名" 802-11-wireless.band a
# a = 5GHz, bg = 2.4GHz
情况D:网卡驱动有已知 bug——升级内核或固件
# 更新固件包
sudo apt update
sudo apt install linux-firmware
# 或尝试更新的内核(Ubuntu Mainline Kernel)
# 注意:慎用,先备份当前内核
Wi-Fi 唤醒断线排查速查
| |
|---|
| sudo modprobe -r <驱动> && sudo modprobe <驱动> |
| sudo systemctl restart NetworkManager |
| nmcli connection modify "名称" 802-11-wireless.band a |
| |
| sudo apt install linux-firmware |
六、挂起被阻止或自动唤醒
谁不让我睡?
# 查看所有持有"唤醒锁"的程序
systemd-inhibit --list
# 输出示例:
# WHO UID USER PID COMM WHAT MODE
# firefox 1000 user 2345 firefox video block
# vlc 1000 user 3456 vlc audio-play block
MODE=block 表示这个程序阻止系统挂起,MODE=delay 表示延迟但不阻止。WHAT 列表示程序声称的阻止原因,video 通常是因为正在播放视频,audio-play 是因为在放音乐。
强制挂起(跳过所有阻止)
# 强制挂起,忽略所有阻止者
sudo systemctl suspend -i
# -i 参数 = --ignore-inhibitors
⚠️ 注意: 强制挂起可能会导致正在下载的文件中断、未保存的工作丢失。不是应急情况不要用。
合盖后自动唤醒排查
# 查看上次唤醒是谁干的
cat /proc/acpi/wakeup
输出示例:
| | |
|---|
PWRB | | |
LID | | |
GLAN | enabled | 有线网卡(Wake on LAN,可能被局域网包唤醒) |
XHC | enabled | |
RP01 | | |
AWAC | | |
如果怀疑某个设备导致了自动唤醒,可以禁用它:
# 禁用有线网卡的 Wake on LAN(换成你的设备名)
echo GLAN | sudotee /proc/acpi/wakeup # 执行一次是禁用,再执行一次是启用,这命令是切换开关)
# 禁用 USB 控制器的唤醒功能
echo XHC | sudotee /proc/acpi/wakeup
💡 提示:/proc/acpi/wakeup 的设置重启后会恢复。要永久禁用,需要写一个 systemd 服务在每次启动时执行。
最常见"自动醒"的原因
| | |
|---|
| | 在 /proc/acpi/wakeup 里禁掉对应 USB 端口 |
| | |
| sudo rtcwake -m show | |
| | sudo rfkill block bluetooth |
七、进阶:定时唤醒(rtcwake)
有时候你可能想让电脑在特定时间自动唤醒,比如半夜自动备份:
# 查看当前有没有定时唤醒
sudo rtcwake -m show
# 设置 60 分钟后自动唤醒
sudo rtcwake -m mem --date +60min
# 设置明天早上 7:00 唤醒
sudo rtcwake -m mem --date"tomorrow 07:00"
# 设置绝对时间唤醒
sudo rtcwake -m mem --date"2026-06-17 08:30:00"
结合 cron 可以实现"下班挂起,明早 8 点自动醒"之类的骚操作。
💡 提示:rtcwake 走的是硬件 RTC(实时时钟),不依赖操作系统运行。即使完全断电,RTC 也会在设定时间唤醒硬件。
总结
| |
|---|
| fallocate 创建 swapfile → 写 fstab → 加内核 resume= 参数 |
| GRUB 加 mem_sleep_default=deep |
| 内核参数加 nvidia.NVreg_PreserveVideoMemoryAllocations=1 + 启用 nvidia-suspend 服务 |
| 设快捷键 + 改 logind 合盖 = hibernate |
| systemd 服务 auto modprobe 或 restart NetworkManager |
| /proc/acpi/wakeup |
| systemd-inhibit --list 查凶手,急了就 systemctl suspend -i |
💡 上篇聊了原理和诊断,这篇聊的是修复。两篇合起来,应该能搞定 90% 的 Linux 休眠问题了。剩下的 10% 大多是特定硬件的问题,去 Arch Wiki 或 Ask Ubuntu 用你的网卡/显卡型号搜一下,大概率有前人踩过坑。
📌 下一篇预告: 《Linux双系统时间不同步》,聊一下Windows 和 Linux 双系统时间打架的问题。