你有没有经历过这样的时刻:手头是一台普通的 x86 笔记本,却拿到了一份 ARM64 架构的国产系统镜像;或者刚分配了一块 RISC-V 开发板,快递还没到,但今晚就要验证一个启动流程。这时候,QEMU 几乎是绕不开的选择。它可以模拟多种硬件架构,也能在 x86 宿主上运行 Linux、Windows 和各类国产操作系统,听起来确实很“万能”。但很多人第一次用它,不是被命令行劝退,就是卡在启动后没有输出、性能慢到无法忍受、图形界面黑屏这一类问题上。
问题到底出在哪?我见过不少初学者把时间花在记一条条可复用的命令上,结果换个场景就失效。真正决定 QEMU 使用体验的,不是你背了多少参数,而是你有没有同时想清楚三件事:架构匹配、加速后端、镜像管理。QEMU 不是“一个虚拟机软件”,而是“硬件模拟器 + 虚拟机监控器”的组合。把这层关系搞明白,后面所有操作才谈得上顺。
1. 先搞清楚 QEMU 到底在解决什么问题
1.1 全系统模拟和虚拟化的分界线
QEMU 有两种完全不同的运行模式:
- 系统模拟器(
qemu-system-*):模拟整台电脑,包括 CPU、内存、外设、中断控制器,可以完整启动一个操作系统。 - 用户态模拟器(
qemu-*):只模拟 CPU 和系统调用接口,用来直接运行另一个架构编译出来的单个程序。
很多人平时说“用 QEMU 跑虚拟机”,默认指的是系统模拟器。真正关键的区别在底层:当 QEMU 以纯软件方式运行时,客户机指令会被 TCG 动态翻译成宿主机架构的指令,所以 x86 主机可以模拟 ARM、RISC-V、MIPS 等不同架构。代价是性能明显偏低。而当你让 QEMU 模拟与宿主相同架构时,它可以调用 KVM(Linux)或 WHPX(Windows)这类硬件虚拟化接口,让虚拟机里的指令尽量直接在真实 CPU 上执行,性能会接近原生。
这个差别决定了你后续所有预期。如果你拿一台 x86 机器去模拟 ARM 系统,就别指望它能像原生虚拟机一样流畅,QEMU 的价值是把“启动链路能不能通”验证出来。如果只是想在 x86 上跑一个 Ubuntu 虚拟机,优先启用 KVM/WHPX 才是正常用法。
1.2 多架构支持带来的真实价值
QEMU 的价值不是“可以多装一个虚拟机”,而是把跨架构的软件验证变成一种可复现的流程。
嵌入式团队在开发 ARM 程序时,可以在 x86 的 CI 机器上用用户态模拟器跑单元测试;内核开发者可以用qemu-system-aarch64先启动内核,确认启动日志和驱动路径;国产操作系统适配人员也可以在拿到真实硬件之前,用 QEMU 完成镜像启动、安装、基础软件验证等工作。这些场景节省的不只是几小时,而是把“必须依赖真实硬件”的前置条件打掉了。
可以这么理解:真实开发板是最终验收环境,QEMU 是白天随时能拿出来做实验的迷你试验台。两者不是替代关系,而是互补关系。
2. 搭建最小运行环境:从安装到第一条启动命令
2.1 安装:不同宿主的常见方式
在 Ubuntu/Debian 系统上,常见安装命令是:
sudo apt update sudo apt install qemu-system在 CentOS/RHEL 系列上,可以使用yum install qemu。不过不同发行版的包拆分方式可能不同,有的会把 x86、ARM、RISC-V 模拟器拆成独立包,所以装完后建议先检查一下:
qemu-system-x86_64 --version qemu-system-aarch64 --version qemu-system-riscv64 --version如果某个架构的模拟器没有随包安装,就需要单独安装对应的 QEMU 包。
Windows 上可以到 QEMU 官网下载安装包,也可以用包管理器。以 winget 为例,可以先搜:
winget search qemu然后根据本机显示的包 ID 安装。安装完成后,把 QEMU 安装目录加入PATH,命令行里才能直接调用。macOS 上如果通过 Homebrew 安装,通常是一条brew install qemu。
这里多说一句:安装本身不是难点,难点在于有人装完发现qemu-system-aarch64不存在,就想当然以为 QEMU 不支持 ARM。实际上多半是包没装全,先检查模拟器文件再下结论。
2.2 跑通第一个虚拟机的“最小命令”
先用一个不带图形界面的 Linux 发行版 ISO 做测试。最简单的启动命令长这样:
qemu-system-x86_64 \ -m 1024 \ -cdrom /path/to/image.iso \ -boot d-m 1024表示分配 1GB 内存,-cdrom挂载光驱镜像,-boot d表示先从光驱启动。第一次验证不要贪大,内存可以先给 1GB,CPU 也可以不加。
如果你想用一块虚拟硬盘来安装系统,先创建磁盘镜像:
qemu-img create -f qcow2 disk.qcow2 20G然后启动:
qemu-system-x86_64 \ -m 2048 \ -hda disk.qcow2 \ -cdrom /path/to/install.iso \ -boot d按提示安装完系统后,再启动时就不需要-cdrom和-boot d了,直接指向硬盘镜像即可。
这个流程是最小可用路径。它的作用不是展示 QEMU 的复杂能力,而是让你先确认:QEMU 本身没问题、镜像没问题、当前的输出方式能看到启动过程。如果这一步都跑不通,后面调网络、调跨架构更无从谈起。
2.3 为什么没有图形界面?输出并不只有窗口
很多人在服务器上跑 QEMU,发现没有窗口弹出,或者弹出一个黑窗口马上就消失,就以为失败了。其实 QEMU 有多种显示输出方式:
- GTK 或 Cocoa 图形窗口,适合本机手动操作。
- VNC,适合远程连接图形桌面。
- Spice,适合需要更丰富远程协议的场景。
- 串口模式,适合纯文本调试和嵌入式场景。
如果你在无显示器服务器上运行,可以加-vnc :1,然后用 VNC 客户端连到宿主机IP:5901。如果不需要图形界面,只想看内核串口日志,可以加-nographic或-serial stdio,让串口输出直接进当前终端。
初学者经常把“没有图形输出”和“虚拟机启动失败”混为一谈。排查时先确认你配置的是哪种输出方式,再看是没输出还是输出后卡住。这两者处理思路完全不同。
3. 真正拉开差距的是加速后端、镜像管理和网络
3.1 KVM、WHPX、TCG 怎么选
加速方式直接决定虚拟机能不能流畅跑。可以先看一张简单的对照表:
| 使用场景 | 模拟器 | 加速方式 | 性能预期 |
|---|---|---|---|
| Linux x86 宿主机跑 x86 虚拟机 | qemu-system-x86_64 | KVM | 接近原生 |
| Windows x86 宿主机跑 x86 虚拟机 | qemu-system-x86_64 | WHPX | 可用,但依赖 Hyper-V 平台组件 |
| x86 宿主机跑 ARM 虚拟机 | qemu-system-aarch64 | TCG | 明显慢,适合功能与启动验证 |
| x86 宿主机跑 RISC-V 虚拟机 | qemu-system-riscv64 | TCG | 适合开发调试,不适合重负载 |
在 Linux 上,先查看 KVM 是否可用:
ls -l /dev/kvm如果这个设备文件不存在,说明 KVM 不可用或未加载内核模块。常见原因有三个:BIOS/固件里关闭了虚拟化、内核没有加载kvm或kvm_amd/kvm_intel模块、当前用户不在kvm用户组里。
在 Windows 上,QEMU 会尝试使用 WHPX(Windows Hypervisor Platform),前提是系统功能里开启了“虚拟机平台”和“Windows 虚拟机监控程序平台”。如果你之前遇到 WSL2 报“此计算机上未启用虚拟化”,那么 QEMU 的 WHPX 也可能同样不可用,因为这两个功能共用底层虚拟化开关。
排查顺序建议是:
- 进入固件设置,确认 CPU 虚拟化(Intel VT-x 或 AMD-V)已开启。
- 在 Windows 功能中启用“虚拟机平台”和“Windows 虚拟机监控程序平台”。
- 重启后执行
systeminfo,查看输出里 Hyper-V 相关要求是否满足。 - 重新运行 QEMU,并在参数中显式指定
-accel whpx,看报错信息。
如果确实没有硬件加速可用的环境,QEMU 会自动落回 TCG,也能运行,只是性能会差很多。但要注意:如果你在参数里写了-accel kvm或-accel whpx,而环境不支持,QEMU 会直接报错,而不是悄悄降级。
3.2 qcow2、raw 和磁盘镜像的增量玩法
磁盘镜像的格式会影响性能、占空间和可维护性。raw 格式最接近物理磁盘,性能好,但占用空间大,也不支持快照。qcow2 是 QEMU 最常用的格式,默认稀疏分配,也就是说创建 20G 的镜像,实际只用多少占多少,还支持快照、后端镜像、压缩等特性。
创建 qcow2 镜像:
qemu-img create -f qcow2 base.qcow2 20G做批量测试时,还可以基于一个基础镜像创建差量镜像:
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 test1.qcow2这样test1.qcow2不复制基础镜像的全部数据,而是把变化记录在差量文件里。多个测试实例可以共享同一个干净的基础系统,互不污染。对于需要反复验证同一套软件行为的场景,这个功能非常实用。
3.3 网络和串口:调试时最容易卡住的两个口
QEMU 默认的用户模式网络(user networking)适合虚拟机共享宿主机网络上网,也适合做端口转发。常见的转发写法:
qemu-system-x86_64 \ -m 2048 \ -drive file=disk.qcow2,format=qcow2 \ -netdev user,id=n1,hostfwd=tcp::2222-:22 \ -device virtio-net-pci,netdev=n1这样宿主机上的2222端口会转发到客户机的22端口,之后你就可以用ssh -p 2222 user@localhost登录虚拟机,不用开图形界面。
串口则更像是嵌入式开发者的“眼耳口鼻”。如果你调试内核或者 bootloader,通常需要把串口映射到终端:
qemu-system-aarch64 ... -serial stdio或直接用-nographic,让 QEMU 把串口输出接到当前终端。这里有一个特别容易踩的坑:客户机内核参数里的console=ttyAMA0是告诉 Linux 内核日志从哪个串口出去,而 QEMU 前端的-serial stdio是告诉 QEMU 把哪个物理串口映射到宿主终端。两边必须对齐,否则你会在终端里什么都看不到。
4. 跨架构模拟:在 x86 上跑 ARM 和 RISC-V
4.1 先区分系统模拟器和用户态模拟器
qemu-system-aarch64是完整系统模拟,可以启动一个完整的 ARM64 Linux 系统。qemu-aarch64是用户态模拟,它只负责运行单个 ARM64 编译的程序,不能启动完整系统。
用户态模拟非常适合做交叉编译后的验证。比如你在一台 x86 机器上用交叉工具链编译了一个 ARM64 程序,想快速确认它能不能运行,就可以用:
qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello-L指定交叉编译工具链的 sysroot 路径,目的是让动态链接器找到正确的依赖库。这个用法在 CI 流水线里很常见,因为不需要启动整个虚拟机,速度更快,资源占用也更小。
不过要注意:用户态模拟只能验证用户态程序,不能验证内核、驱动和硬件相关逻辑。如果你想跑一个完整系统,仍然需要qemu-system-aarch64。
4.2 跑一个 ARM Linux 系统的基础流程
完整跑 ARM64 Linux 有两种常见路径:
- 使用发行版提供的云镜像或 QEMU 镜像,直接作为磁盘启动。
- 手动准备内核、initrd 和根文件系统,用
-kernel参数手动引导。
后者更适合内核调试,示意命令如下:
qemu-system-aarch64 \ -M virt \ -cpu cortex-a57 \ -smp 2 \ -m 2048 \ -kernel Image \ -initrd initrd.img \ -append "console=ttyAMA0 root=/dev/vda rw" \ -drive file=rootfs.qcow2,format=qcow2,if=virtio \ -serial stdio这里的Image是 ARM64 Linux 内核的常见产物,但在不同发行版、不同构建系统里文件名可能不一样。-M virt是 QEMU 提供的一个通用 ARM 虚拟开发板模型,外设模型相对简单,最适合做纯软件模拟和调试。
如果你刚接触跨架构模拟,我建议先使用现成的云镜像,而不是手动编译内核。手动编译内核需要处理交叉工具链、内核配置、initramfs 等多个变量,哪一个有问题都会让你误以为 QEMU 出了问题。先用现成镜像把启动链路跑通,再逐步引入自己的内核,会顺利很多。
4.3 RISC-V 模拟适合干什么
RISC-V 在 QEMU 里的成熟度这几年提升很快,比如-M virt机器模型已经能跑 OpenSBI、U-Boot 和 Linux。可以用下面的命令思路启动一个 RISC-V 64 系统:
qemu-system-riscv64 \ -M virt \ -m 2G \ -smp 2 \ -kernel /path/to/Image \ -append "console=ttyS0" \ -drive file=rootfs.qcow2,format=qcow2,if=virtio \ -serial stdio但要注意边界:QEMU 模拟的 RISC-V 外设模型没有 x86 那么丰富,很多开发板上的私有外设、专有接口、复杂中断控制器都无法完全模拟。它更适合用来验证启动流程、跑基础 Linux 命令、做内核最小配置调试;如果要做硬件相关驱动的全量验证,还是需要在真实板子上跑。
5. 在 Windows 上使用 QEMU 会遇到哪些坑
5.1 虚拟化未启用:WSL2 和 WHPX 共用一个开关
Windows 下使用 QEMU,最常见的报错就是和虚拟化相关的提示。比如 QEMU 启动时报“此平台不支持虚拟化的 AMD-V/RVI”,或者 WSL2 之前已经报过“此计算机上未启用虚拟化”。这两类问题往往指向同一个底层原因:系统虚拟化开关或 Windows 功能没有开全。
我建议按这个顺序排查:
- 重启进入 BIOS/固件设置,确认 Intel VT-x 或 AMD-V 已开启。
- 在 Windows 功能里开启“虚拟机平台”和“Windows 虚拟机监控程序平台”。
- 重启后运行
systeminfo,看 Hyper-V 要求部分是否提示“已检测到虚拟机监控程序”。 - 再次用
-accel whpx显式启动 QEMU,观察报错是否变化。
如果第 3 步仍然显示未检测到,问题通常出在固件开关或 Windows 功能没有真正生效。不要急着换 QEMU 版本,先确认这两个基础项。
5.2 安装依赖缺失:VC++ 运行库问题
有些用户在 Windows 上安装 QEMU 时会遇到系统提示缺少 Microsoft Visual C++ 运行库。常见现象是安装包校验没问题,但安装到一半报缺少某个运行库组件。这通常不是 QEMU 包的问题,而是当前系统缺失公共运行库。
处理思路比较简单:去微软官网下载并安装最新的 Visual C++ Redistributable,再重新安装 QEMU。如果系统里既有 32 位也有 64 位程序,最好把 x86 和 x64 两个版本都装上,避免不同软件各取所需。
5.3 在 Windows 上跑 Linux 虚拟机,还是直接用 WSL2?
这是一个经常被问的问题。WSL2 和 QEMU 定义不同:WSL2 是一套与 Windows 深度集成的 Linux 运行环境,适合跑终端命令、脚本、容器和常见开发工具;QEMU 是通用虚拟机管理工具,适合启动完整操作系统、调试内核、模拟不同硬件架构。
如果你需要的是一个完整的 Linux 桌面环境,或者要做内核启动调试,QEMU 更合适;如果只是想要一个顺手、省资源的 Linux 命令行环境,WSL2 通常更轻量。两者不是替代关系,可以共存。WSL2 出现问题,并不代表 QEMU 也会出现问题,因为两者虽然都依赖底层虚拟化,但用户态组件、配置路径和启动方式并不同。
6. 国产系统和嵌入式场景下,QEMU 怎么用才顺手
6.1 先确认镜像架构,再选择模拟器
现在不少国产操作系统会同时提供 x86_64 和 aarch64 两种架构的镜像,比如麒麟 V10、统信 UOS 等。在 QEMU 里验证这些系统,第一件事不是运行,而是确认镜像架构。
如果宿主是 x86_64,要跑 aarch64 版镜像,启动命令要使用qemu-system-aarch64,而且只能以 TCG 纯软件方式模拟,性能会明显低于同架构。为了获得更好的体验,优选和宿主架构相同的镜像版本。
如果你只是想验证某个软件在国产系统上的兼容性,可以用用户态模拟器更快地跑单个程序,而不需要启动完整桌面环境。但如果要验证安装流程、桌面环境、服务启动这些系统级行为,还是用完整系统模拟。
6.2 串口和-nographic是嵌入式调试的第一块基石
在嵌入式 Linux 开发中,QEMU 最常用的反而不是图形界面,而是串口。
比如很多基于 ARM 的开发板 BSP 文档里,启动 QEMU 的命令类似:
qemu-system-arm \ -M vexpress-a9 \ -m 256M \ -kernel zImage \ -dtb vexpress-v2p-ca9.dtb \ -append "console=ttyAMA0" \ -nographic用串口模式而不是图形窗口,更接近真实开发环境:启动阶段有没有内核日志、分区能否挂载、串口交互是否正常,一眼就能看出来。同时也可以放到脚本里自动收集日志,方便做回归验证。
6.3 用快照把测试环境“冻结”下来
做国产系统适配时,经常需要反复进入一个已知状态,比如“刚装完操作系统”“已安装依赖”“已执行完一次安装脚本”。用 qcow2 镜像加快照,可以把这个状态保存下来,测试结束后快速恢复,避免一次次重装系统。
QEMU monitor 里可以使用savevm和loadvm;也可以通过外部命令创建快照:
qemu-img snapshot -c clean-base disk.qcow2恢复时用:
qemu-img snapshot -a clean-base disk.qcow2这种“先做好干净状态,再放心折腾”的思路,比每次从安装介质重新开始高效得多。
7. 排错手册:我该从哪里查起?
7.1 一个四层定位框架
遇到 QEMU 问题时,不要急着调参数。先按下面的顺序把问题定位到某一层:
- 现象层:是完全启动不了,还是启动了但没输出、黑屏、网络不通、性能慢?
- 架构层:QEMU 的模拟器架构、客户机镜像架构、guest 内核架构三者是否一致?
- 加速层:是否成功启用 KVM/WHPX,还是落回了 TCG?显式指定
-accel后有没有报错? - 配置层:内存、CPU、磁盘格式、设备模型、串口参数是否和客户机匹配?
这个顺序的价值在于:很多新手一上来就怀疑参数写错了,结果问题根本不在参数,而在架构不匹配。比如用qemu-system-x86_64去启动一个 ARM64 镜像,参数再正确也起不来。
7.2 常见报错与初步处理思路
下面是一些常见场面和初步排查方向:
- 启动时报
Failed to initialize KVM:KVM 不可用或权限不足。检查/dev/kvm、当前用户组,或者临时改用-accel tcg验证是不是加速层问题。 - 启动后黑屏无输出:先确认输出方式是窗口、VNC 还是串口。如果是串口,检查 guest 内核 console 参数是否和
-serial对应。 - 报
Guest has not initialized the display:可能只是显示初始化慢,也可能显卡驱动没起来,不要急着判定死机,多等几秒或改用串口模式观察。 - 磁盘镜像无法启动:用
qemu-img info disk.qcow2查看镜像格式、大小、快照信息,确认不是文件损坏或格式不匹配。
7.3 性能慢,优先检查这几项
性能慢是最常见的劝退点。优先检查五件事:
- 是否用了硬件加速:如果 QEMU 落回 TCG,性能会大幅下降。确认
-accel参数和宿主支持状态。 - 是否用了 virtio 设备:Linux 客户机尽量使用 virtio 磁盘和网卡,设备模型差异对吞吐影响很大。
- 磁盘格式:raw 格式通常比 qcow2 更快,但功能少。如果快照不是刚需,可以在追求性能时选用 raw。
- CPU 型号设置:KVM 模式下可以用
-cpu host,TCG 模式下通常用-cpu max。手动指定一个过低的老 CPU 模型会限制指令集。 - 内存是否足够:给客户机分配的内存不足时系统会频繁换页,但也不能把宿主机内存全部占满,否则两个系统一起卡。
8. 把 QEMU 从“临时试一下”变成工作流的一部分
8.1 先跑通最小系统,再叠加需求
我建议所有 QEMU 新手都遵循同一个节奏:先跑通最小系统,再逐步加功能。不要一开始就把网络、共享目录、声卡、USB 重定向全部配满。每一步增加一个变量,出问题的时候才能快速判断是哪一层引入的。
一个典型顺序是:
- 用默认参数跑通
qemu-system-x86_64,确认系统能启动。 - 加入 virtio 磁盘和 virtio 网卡,验证性能和网络。
- 加入端口转发和 SSH,让虚拟机可以无人值守访问。
- 再加入 VNC 或 Spice,处理图形界面需求。
- 最后再考虑跨架构模拟、多虚拟机、自动化脚本。
这个过程看起来很基础,但恰恰是最稳的。
8.2 用脚本固化命令
当一条 QEMU 命令经过调试已经稳定可用后,把它固化成脚本,而不是每次手动敲一遍。脚本化的好处不只是省时间,还能把参数、镜像路径、端口号这些关键信息变成可维护的配置。
一个简单的启动脚本可以长这样:
#!/bin/bash exec qemu-system-x86_64 \ -m 2048 \ -smp 2 \ -drive file=disk.qcow2,format=qcow2,if=virtio \ -netdev user,id=n1,hostfwd=tcp::2222-:22 \ -device virtio-net-pci,netdev=n1 \ -display none \ -serial stdio注意脚本里的镜像路径、虚拟化加速选项、端口号都可能随着环境变化,不要做成一个死模板。
8.3 把 QEMU 纳入 CI 或自动化测试
再进一步,QEMU 完全可以成为自动化测试的一部分。在软件开发中,你可以用 QEMU 启动一个干净的测试系统,在虚拟机里执行安装脚本、运行测试用例、检查服务状态,然后通过快照恢复到初始状态。这样既避免了宿主机被测试污染,又能保证每次测试从同一个基线开始。
跨架构验证也同样适用:在 x86 的 CI 机器上,用qemu-system-aarch64启动一个 ARM64 虚拟机,跑完测试后直接销毁。速度不一定快,但能提前发现很多“换个架构就崩”的问题。这类问题如果等到真实硬件才暴露,排查成本往往高得多。
QEMU 真正值得长期掌握的地方,是它让你从“等硬件”变成“先模拟验证”。从嵌入式交叉编译到国产系统适配,从内核调试到桌面虚拟化,它都是一层很可靠的地基。如果你正准备开始,我建议你先不要急着下载一个大而全的系统镜像,而是找一个小型内核和一个根文件系统,用-nographic把一条串口日志跑通。等你看到第一行 Linux 启动日志出现在终端里,你对 QEMU 的理解,就已经超过大多数只看过教程的人了。