Skip to content

ARM64 Windows 虚拟机关机黑屏很久(快速启动) ​

在 ARM64 主机上运行 Windows 11 ARM 虚拟机时,从 Windows 里点击关机后,虚拟机长时间黑屏,过几十秒到几分钟才真正关掉。虚拟机开机时间越长,卡得越久。Linux 虚拟机没有这个问题。

表现 ​

  1. 虚拟机

关机后一直黑屏,不响应任何操作,最后才自己断电。

  1. 主机
  • 主机日志(dmesg、journalctl)里看不到任何报错
  • 用 top -H -p $(cat /var/run/qemu-server/<vmid>.pid) 查看,所有 CPU n/KVM 线程都占满 100%
  1. 确认方法

在卡住时运行下面的命令,统计 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

原因 ​

  1. Windows 默认开启了"快速启动"。点击关机时,Windows 实际上是把内核会话休眠到 hiberfil.sys。
  2. 写休眠文件时,Windows 会冻结其他 CPU,只用一个 CPU,在关中断的状态下用 diskdump.sys 轮询磁盘。每次轮询之间调用 KeStallExecutionProcessor 等待一小段时间。
  3. ARM64 版 Windows 用 PMU 周期计数器 PMCCNTR_EL0 计时这段等待。在 KVM 下,读这个寄存器每次都会陷入宿主机,而虚拟 PMU 只统计 guest 态的周期,陷入后在宿主机上花的时间不算。
  4. 实测在这个过程中,计数器只按真实时间的约 2.6% 在走,每次等待都被拉长约 38 倍,所以写休眠文件从几秒变成了几分钟。

解决方案 ​

在 Windows 中关闭休眠(会同时关闭快速启动)。用管理员身份打开 PowerShell 或命令提示符,执行:

powercfg /h off

之后关机会在几秒内完成。

如果只想关闭快速启动、保留休眠功能,可以在"控制面板 → 电源选项 → 选择电源按钮的功能 → 更改当前不可用的设置"里,取消勾选"启用快速启动"。