ARM64 Windows 虚拟机关机黑屏很久(快速启动)
在 ARM64 主机上运行 Windows 11 ARM 虚拟机时,从 Windows 里点击关机后,虚拟机长时间黑屏,过几十秒到几分钟才真正关掉。虚拟机开机时间越长,卡得越久。Linux 虚拟机没有这个问题。
表现
- 虚拟机
关机后一直黑屏,不响应任何操作,最后才自己断电。
- 主机
- 主机日志(
dmesg、journalctl)里看不到任何报错 - 用
top -H -p $(cat /var/run/qemu-server/<vmid>.pid)查看,所有CPU n/KVM线程都占满 100%
- 确认方法
在卡住时运行下面的命令,统计 1 秒内的 VM exit 次数(把 <vmid> 换成虚拟机 ID):
pid=$(cat /var/run/qemu-server/<vmid>.pid)
d=$(ls -d /sys/kernel/debug/kvm/${pid}-*)
e=$(cat $d/exits); w=$(cat $d/wfi_exit_stat); sleep 1
echo "exits/s=$(( $(cat $d/exits) - e )) wfi/s=$(( $(cat $d/wfi_exit_stat) - w ))"如果 exits/s 达到每秒上百万次,同时 wfi/s 为 0,就命中了这个问题。
exits/s=1141905 wfi/s=0原因
- Windows 默认开启了"快速启动"。点击关机时,Windows 实际上是把内核会话休眠到
hiberfil.sys。 - 写休眠文件时,Windows 会冻结其他 CPU,只用一个 CPU,在关中断的状态下用
diskdump.sys轮询磁盘。每次轮询之间调用KeStallExecutionProcessor等待一小段时间。 - ARM64 版 Windows 用 PMU 周期计数器
PMCCNTR_EL0计时这段等待。在 KVM 下,读这个寄存器每次都会陷入宿主机,而虚拟 PMU 只统计 guest 态的周期,陷入后在宿主机上花的时间不算。 - 实测在这个过程中,计数器只按真实时间的约 2.6% 在走,每次等待都被拉长约 38 倍,所以写休眠文件从几秒变成了几分钟。
解决方案
在 Windows 中关闭休眠(会同时关闭快速启动)。用管理员身份打开 PowerShell 或命令提示符,执行:
powercfg /h off之后关机会在几秒内完成。
如果只想关闭快速启动、保留休眠功能,可以在"控制面板 → 电源选项 → 选择电源按钮的功能 → 更改当前不可用的设置"里,取消勾选"启用快速启动"。