本文要点
- Linux 下的硬件信息有三条来源:
/proc(内核导出的文本)、/sys(设备模型,一个文件一个属性)、用户态工具(lscpu/lsblk/lspci/dmidecode),三者经常互相矛盾,得知道该信谁 - 识别虚拟机最快的三条命令:
systemd-detect-virt直接输出kvm、dmesg | grep -i "Hypervisor detected"有开机记录、/proc/cpuinfo的 flags 里带hypervisor标志 dmidecode必须 root,真实原因是/sys/firmware/dmi/tables/下那两个文件权限是 0400;而/sys/devices/virtual/dmi/id/是 0444 世界可读——两者读的是同一份 SMBIOS 数据,普通用户走后者就行- ⚠️
lsblk的ROTA列在虚拟机上不可信:virtio 磁盘上报的ROTA=1并不代表它是机械盘,TRAN列也是空的 - ⚠️ SMBIOS 里全是模拟数据:本机 dmidecode 报处理器
Max Speed: 2000 MHz,而 CPUID 报的型号是 2.60GHz 的 Xeon Platinum 8272CL——性能相关问题信lscpu,别信 dmidecode - 缓存和 NUMA 拓扑是宿主机的:1 核的虚拟机报告了 35.8 MiB 的 L3(8272CL 的 L3 正是 35.75 MB),别拿它推算自己的资源
- 虚拟化还会渗透到设备命名:网卡驱动是
virtio_net、ethtool eth0报Speed: Unknown!、USB 总线上挂着一块QEMU USB Tablet
Linux 硬件信息采集:从 lscpu 到 dmidecode 识别物理机与虚拟机
买机器前想知道配置够不够、迁移前想确认目标机硬件、排障时想知道驱动有没有绑上——这些都叫「采集硬件信息」。麻烦的地方在于同一份硬件,Linux 会给你三套说法,而且它们在虚拟化环境下经常对不上。
这篇文章在一台 1 核 2G 的 NAT 小机(Ubuntu 22.04、内核 5.15.0-30-generic)上把三条路径都走一遍,顺带回答一个很实用的问题:怎么判断你手里这台到底是物理机还是虚拟机。答案不止一条命令,而是五组互相印证的证据。
硬件信息的三条来源
| 来源 | 形态 | 特点 |
|---|---|---|
/proc | 内核态实时导出的文本 | 反映当前内核看到的硬件,如 /proc/cpuinfo、/proc/meminfo |
/sys | 设备模型,一个文件一个属性 | 结构最规整,权限粒度细,适合脚本读取 |
| 用户态工具 | lscpu/lsmem/lsblk/lspci/lsusb/dmidecode | 把上面两者整理成人话,但各自有自己的数据源和盲区 |
关键认知是:这三条路径的信息源并不相同。lscpu 的数据来自 CPUID 指令和 /proc/cpuinfo;dmidecode 的数据来自 BIOS/UEFI 填好的 SMBIOS 表;lsblk 来自内核块设备层和 udev 数据库。搞混了就会得出错误结论——后面第六节有个现成的例子。
CPU:lscpu 把 /proc/cpuinfo 整理成人话

lscpu | grep -E "Model name|^CPU\(s\)|Thread\(s\) per core|Core\(s\) per socket|Socket\(s\)|Hypervisor vendor|Virtualization type"; echo "--- 虚拟机检测:"; systemd-detect-virt; dmesg | grep -i "Hypervisor detected"CPU(s): 1
Model name: Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 1
Hypervisor vendor: KVM
Virtualization type: full
--- 虚拟机检测:
kvm
[ 0.000000] Hypervisor detected: KVMlscpu 不带参数输出很长,这里挑了几行关键的。几个读法:
Socket(s) × Core(s) per socket × Thread(s) per core= 总 vCPU 数:1 × 1 × 1 = 1。反过来,如果你看到Socket(s): 1、Core(s) per socket: 8、Thread(s) per core: 2,那就是 16 个逻辑 CPU。这比直接看CPU(s):更能说明机器的物理形态。Hypervisor vendor: KVM:这一行是 CPUID 直接告诉你的,只有当 Linux 跑在 hypervisor 之上才会出现。物理机上这一行根本不存在——它不是一个显示为none的字段,而是整个字段都没有。这是判断虚拟机的第一手证据。Virtualization type: full:全虚拟化。与之对应的para表示半虚拟化。
顺便看几个容易被忽略的字段:
lscpu | grep -E "Address sizes|BogoMIPS|CPU family|^Model:|Stepping|L1d|L2 |L3 |NUMA"Address sizes: 46 bits physical, 48 bits virtual
CPU family: 6
Model: 85
Stepping: 7
BogoMIPS: 5187.81
L1d cache: 32 KiB (1 instance)
L2 cache: 1 MiB (1 instance)
L3 cache: 35.8 MiB (1 instance)
NUMA node(s): 1
NUMA node0 CPU(s): 0Address sizes: 46 bits physical:物理地址总线 46 位,理论上限 64TB 内存。虚拟机里这个值来自宿主机 CPU,和你能买多少内存无关。CPU family / Model / Stepping:6 / 85 / 7是识别 CPU 微架构的硬指纹,比型号字符串更可靠(云厂商经常改写型号字符串)。BogoMIPS:内核启动时校准出来的「空转速度」,只适合横向对比同型号机器,不是性能指标。- ⚠️
L3 cache: 35.8 MiB值得单独说:这台虚拟机只有 1 个 vCPU,却报告了 35.8 MiB 的 L3。Xeon Platinum 8272CL 的 L3 正好是 35.75 MB——KVM 把宿主机的缓存拓扑原样透传了进来。所以虚拟机里的缓存大小和 NUMA 拓扑反映的是宿主机,别拿它推算自己的资源边界。
还有个常被漏掉的证据藏在 flags 里:
grep -o -m1 "hypervisor.*" /proc/cpuinfo | cut -c1-60hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_singlehypervisor 这个 CPU 标志位是内核在检测到 CPUID 的 hypervisor present 位后加进去的,物理机上不会有。它和 lscpu 的 Hypervisor vendor 同源,但 grep 一下更快——写脚本时尤其方便。
最后别忘了 lscpu 还会列出漏洞缓解状态:
lscpu | grep -A20 "^Vulnerability"Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2: Mitigation; Enhanced IBRS, IBPB conditional, RSB filling
Vulnerability Tsx async abort: Mitigation; TSX disabledNot affected 说明该 CPU 型号硬件上不受影响,Mitigation 说明靠软件手段缓解(通常有性能代价)。虚拟机上这份列表还受宿主机微码和 KVM 配置影响——如果你在排查「为什么这台机器比那台慢」,这一节值得对照着看。CPU 侧的深度剖析可以看 perf 性能剖析:从 perf stat 到采样报告定位 CPU 热点。
内存:free、lsmem 与 meminfo 三角验证
free -h; echo "--- lsmem:"; lsmem; echo "--- meminfo:"; grep -E "MemTotal|MemAvailable|SwapTotal" /proc/meminfo total used free shared buff/cache available
Mem: 1.9Gi 184Mi 218Mi 0.0Ki 1.5Gi 1.6Gi
Swap: 0B 0B 0B
--- lsmem:
RANGE SIZE STATE REMOVABLE BLOCK
0x0000000000000000-0x000000007fffffff 2G online yes 0-15
Memory block size: 128M
Total online memory: 2G
Total offline memory: 0B
--- meminfo:
MemTotal: 2025116 kB
MemAvailable: 1641164 kB
SwapTotal: 0 kB三处数字需要对齐看:
free说1.9Gi、lsmem说2G、meminfo说2025116 kB。这三个不矛盾:2025116 kB ÷ 1024 ÷ 1024 ≈ 1.93 GiB,free -h按 GiB 显示并保留一位小数就是1.9Gi,而lsmem按内存块向上取整到2G。报数时想精确就用kB值。MemAvailable: 1641164 kB才是「还能用多少」,free列里的218Mi只是完全没被动过的内存。Linux 会把空闲内存拿去做页缓存(buff/cache高达1.5Gi),这部分随时可以回收,所以真实可用量看available。Memory block size: 128M/REMOVABLE: yes:内存被切成 16 个 128MB 的块,标记为可移除。这是内存热插拔的粒度——虚拟机上这个值通常很小(方便 balloon 驱动动态调整),物理服务器上常见 1GB 或更大。SwapTotal: 0 kB:这台机器没有交换空间。一旦MemAvailable见底就是直接触发 OOM Killer,没有缓冲。内存侧的排查套路见 Linux 内存排查:从 free 到 /proc/meminfo 与 OOM Killer 定位。
普通用户读 /proc/meminfo 不需要任何权限,sudo -u nobody head -1 /proc/meminfo 照样能出 MemTotal。
磁盘:lsblk 的 ROTA 与 TRAN 有坑
lsblk -d -o NAME,SIZE,ROTA,TYPE,TRAN,MODELNAME SIZE ROTA TYPE TRAN MODEL
loop0 61.9M 1 loop
loop1 79.9M 1 loop
sr0 394K 1 rom QEMU CD-ROM
vda 8G 1 disk(这里滤掉了几个 snap 挂载用的 loop 设备,输出更干净。)
ROTA=1表示「可旋转」,按设计是用来区分机械盘(1)和固态盘(0)的。但看vda——虚拟磁盘也报了ROTA=1。virtio-blk 默认不上报 rotational 属性,内核就取了保守默认值。所以在云服务器上用ROTA判断「这块盘是不是 SSD」基本无效,得去问云厂商或者实测 IOPS(fio 磁盘性能测试:从顺序吞吐到 4K 随机 IOPS 的存储基准)。TRAN列全空是另一个信号:SATA 盘会显示sata、NVMe 显示nvme、USB 显示usb,而 virtio 设备不属于任何一种物理总线,所以这里是空的。sr0的MODEL是QEMU CD-ROM——这台机器上根本没有物理光驱,这个「光驱」是 QEMU 模拟出来的。设备名里带着QEMU三个字母,是虚拟化最直白的签名。
想追这块盘挂在哪个总线上,用 udevadm 读属性:
udevadm info -q property -p /sys/block/vda | grep -E "DEVTYPE|ID_PATH|ID_BUS"DEVTYPE=disk
ID_PATH=pci-0000:00:05.0ID_PATH=pci-0000:00:05.0 直接把这块盘定位到了 PCI 地址 0000:00:05.0——拿这个地址去 lspci 里查,就能对上是哪个控制器(见下一节)。这套「从设备名追到物理位置」的方法,和 lsof 进程文件排查:从打开文件到端口占用的完整指南 里追文件占用是同一个思路。
总线:lspci -k 看设备与驱动绑定

lspci -k | grep -A3 "Ethernet controller"; echo "--- 块设备:"; lsblk -d -o NAME,SIZE,ROTA,TYPE,TRAN,MODEL | grep -v loop; echo "--- 网卡驱动:"; ethtool -i eth0 | head -300:11.0 Ethernet controller: Red Hat, Inc. Virtio network device
Subsystem: Red Hat, Inc. Virtio network device
Kernel driver in use: virtio-pci
--- 块设备:
NAME SIZE ROTA TYPE TRAN MODEL
sr0 394K 1 rom QEMU CD-ROM
vda 8G 1 disk
--- 网卡驱动:
driver: virtio_net
version: 1.0.0
firmware-version:lspci -k 比 lspci 多出的那几行 Kernel driver in use 极其实用——排障时最常见的两类问题就是「设备没被识别」和「设备识别了但驱动没绑上」,这一行直接给出答案。如果某个设备这里是空的,说明内核没有加载对应驱动。
这台机器的完整 PCI 设备清单是这样的:
lspci00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.2 USB controller: Intel Corporation 82371SB PIIX3 USB [Natoma/Triton II] (rev 01)
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Cirrus Logic GD 5446
00:03.0 SCSI storage controller: Red Hat, Inc. Virtio SCSI
00:04.0 Communication controller: Red Hat, Inc. Virtio console
00:05.0 SCSI storage controller: Red Hat, Inc. Virtio block device
00:06.0 Unclassified device [00ff]: Red Hat, Inc. Virtio memory balloon
00:11.0 Ethernet controller: Red Hat, Inc. Virtio network device一眼就能看出是虚拟机:440FX/PIIX3 是 1996 年的 Intel 440FX 芯片组(QEMU 的 i440fx 机型就是照它模拟的)、显卡是 Cirrus Logic GD 5446(1995 年的 2D 显卡,KVM 的默认模拟显卡之一)、四个 Virtio 设备是半虚拟化驱动。在真机上,你不会同时看到这几样东西。
其中 00:05.0 Virtio block device 正好对上了上一节 udevadm 读到的 ID_PATH=pci-0000:00:05.0——磁盘 → 总线地址 → PCI 设备这条链路就串起来了。
网卡还可以再深挖一层,ethtool -i 看驱动信息:
ethtool -i eth0driver: virtio_net
version: 1.0.0
firmware-version:
bus-info: 0000:00:11.0bus-info: 0000:00:11.0 又和 lspci 里的 00:11.0 Ethernet controller 对上了。而 firmware-version 是空的——虚拟网卡没有固件,这也是一处环境特征。
顺带一个常见困惑:ethtool eth0 查速率会得到 Speed: Unknown!、Duplex: Unknown! (255)。这不是故障,是虚拟网卡没有物理链路层,协商速率这个概念不适用;Link detected: yes 说明链路本身是通的。想测真实吞吐量得靠打流工具,网卡自报的速率在虚拟化环境里参考价值有限(HTTP 压测:从 ApacheBench 到 wrk 的 Web 性能测量)。
USB 总线也别漏掉:
lsusbBus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd QEMU USB Tablet
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hubQEMU USB Tablet 是 QEMU 提供给 VNC/SPICE 控制台用的绝对坐标指针设备——服务器上当然没有「USB 数位板」,它纯粹是为了让远程控制台的鼠标不飘。厂商名直接写着 QEMU。
整机身份:dmidecode 与 SMBIOS 表
前面看的都是「内核眼里的硬件」,dmidecode 换了个视角:它读的是 BIOS/UEFI 在开机时填好的 SMBIOS 表,也就是主板厂商给自己机器写的「身份证」。

dmidecode -t system | grep -E "Manufacturer|Product Name|Version|Family"; echo "--- BIOS:"; dmidecode -t bios | grep -E "Vendor|Version|Release Date"; echo "--- 免 root 的 /sys 读法:"; cat /sys/devices/virtual/dmi/id/product_name /sys/devices/virtual/dmi/id/bios_vendor Manufacturer: Red Hat
Product Name: KVM
Version: RHEL 7.6.0 PC (i440FX + PIIX, 1996)
Family: Red Hat Enterprise Linux
--- BIOS:
Vendor: SeaBIOS
Version: 1.16.0-1.module_el8.7.0+1140+ff0772f9
Release Date: 04/01/2014
--- 免 root 的 /sys 读法:
KVM
SeaBIOS-t 后面跟类型,常用的几张表:
| 类型 | 内容 |
|---|---|
bios | BIOS/UEFI 厂商、版本、发布日期 |
system | 整机厂商、产品名、序列号、UUID |
baseboard | 主板信息 |
chassis | 机箱类型 |
processor | 处理器插槽、厂商、速度、核心数 |
memory | 每根内存条的容量、类型、频率、插槽位置 |
Manufacturer: Red Hat + Product Name: KVM + Vendor: SeaBIOS 三件套,是 QEMU/KVM 虚拟机的标准签名(QEMU 用开源 BIOS 实现 SeaBIOS 充当固件)。
为什么 dmidecode 非要 root
很多人被 dmidecode 的权限卡过。真实原因可以直接查出来:
ls -l /sys/firmware/dmi/tables/; sudo -u nobody dmidecode -t system 2>&1 | head -3total 0
-r-------- 1 root root 476 Sep 15 21:00 DMI
-r-------- 1 root root 31 Sep 15 21:00 smbios_entry_point
# dmidecode 3.3
/sys/firmware/dmi/tables/smbios_entry_point: Permission denied
Scanning /dev/mem for entry point.
/dev/mem: Permission denied/sys/firmware/dmi/tables/ 下两个文件的权限是 0400(只有 root 可读),普通用户读不到;dmidecode 退而求其次去扫 /dev/mem,那里的权限更严。两条路都堵死,所以必须 sudo。
免 root 的替代方案
但 SMBIOS 里的常用字段其实有世界可读的出口:
ls -l /sys/devices/virtual/dmi/id/product_name; sudo -u nobody cat /sys/devices/virtual/dmi/id/product_name-r--r--r-- 1 root root 4096 Sep 11 21:05 /sys/devices/virtual/dmi/id/product_name
KVM/sys/devices/virtual/dmi/id/ 目录下每个文件对应一个 SMBIOS 字段,权限是 0444(所有人可读)。sudo -u nobody cat 照样能读出 KVM。写脚本采集资产信息时,能用 /sys 就别调 dmidecode——不用提权,输出还更规整。
⚠️ 陷阱:SMBIOS 里全是模拟数据
这是本文最值得记住的一条。看 dmidecode -t processor 的输出:
dmidecode -t processor | grep -E "Version|Max Speed|Current Speed|Core Count|Thread Count" Version: RHEL 7.6.0 PC (i440FX + PIIX, 1996)
Max Speed: 2000 MHz
Current Speed: 2000 MHz
Core Count: 1
Thread Count: 1Max Speed: 2000 MHz。可 lscpu 明明说这是一颗 2.60GHz 的 Xeon Platinum 8272CL。
两个都没撒谎,但只有一个是真的。 lscpu 的型号来自 CPUID 指令,是 CPU 硬件自报家门;dmidecode 的 Max Speed 来自 QEMU 填进 SMBIOS 表的一个固定值——它压根没打算模拟真实的频率。同理,Version: RHEL 7.6.0 PC 是 QEMU 的 i440fx 机型写死的机型字符串,和实际跑什么系统毫无关系。
所以:性能、容量、拓扑相关问题信 lscpu//proc;资产编号、序列号、机箱型号这类问题才信 dmidecode。
同一份表里的内存信息也是模拟的:
dmidecode -t memory | grep -E "Size|Form Factor|Locator|Type:|Speed|Manufacturer" Size: 2 GB
Form Factor: DIMM
Locator: DIMM 0
Type: RAM
Speed: Unknown
Manufacturer: Red Hat
Configured Memory Speed: UnknownSize: 2 GB 这个大方向是对的(虚拟机的内存确实配了 2GB,和 lsmem 对得上),但 Speed: Unknown、Manufacturer: Red Hat 说明内存条的厂商和频率是编不出来的——虚拟机没有真实内存条,QEMU 只能填空值。Form Factor: DIMM 更是纯装饰。
把证据串起来:判断物理机还是虚拟机
现在可以系统回答开头那个问题了。不要只信一条命令,交叉验证才站得住:
| 证据 | 命令 | 本机结果 | 物理机上会是什么 | |
|---|---|---|---|---|
| 虚拟化检测 | systemd-detect-virt | kvm | none | |
| 开机日志 | `dmesg \ | grep -i "Hypervisor detected"` | Hypervisor detected: KVM | 无输出 |
| CPU 标志位 | grep -c hypervisor /proc/cpuinfo | 1 | 0 | |
| SMBIOS 身份 | dmidecode -t system | Manufacturer: Red Hat / Product Name: KVM | 真实整机厂商(Dell、Supermicro…) | |
| PCI 设备 | `lspci \ | grep -i virtio` | 4 个 Virtio 设备 | 无 |
systemd-detect-virt 一条命令就能出结果,最省事;但它依赖 systemd 的环境判断,某些精简系统或容器环境下可能不准,所以另外四条是它的后手。
反过来,在物理机上你会看到:systemd-detect-virt 输出 none、lscpu 里没有 Hypervisor vendor 那一行、lspci 里出现真实的网卡(Intel I350、Mellanox 之类)和 NVMe 控制器、dmidecode -t system 报出具体品牌型号。
这台机器的硬件画像
把上面所有输出汇总成一张表:
| 项目 | 值 | 来源 |
|---|---|---|
| 虚拟化平台 | KVM(全虚拟化) | systemd-detect-virt、lscpu |
| 固件 | SeaBIOS 1.16.0 | dmidecode -t bios |
| 机型 | QEMU i440fx(440FX + PIIX3) | lspci、dmidecode -t system |
| CPU 型号 | Intel Xeon Platinum 8272CL @ 2.60GHz | lscpu(CPUID) |
| vCPU | 1(1 插槽 × 1 核 × 1 线程) | lscpu |
| L3 缓存 | 35.8 MiB(宿主机的) | lscpu |
| 内存 | 2025116 kB ≈ 1.93 GiB,16 × 128MB 可移除块 | /proc/meminfo、lsmem |
| 交换空间 | 无 | /proc/meminfo |
| 磁盘 | 8G virtio-blk,挂在 PCI 00:05.0 | lsblk、udevadm |
| 网卡 | virtio-net,挂在 PCI 00:11.0 | lspci -k、ethtool -i |
| 显卡 | Cirrus Logic GD 5446(模拟) | lspci |
| 光驱 | QEMU CD-ROM(模拟) | lsblk |
采集系统信息、做资产盘点时,这类表格可以顺手用一个脚本生成——lscpu、lsblk、/proc/meminfo 都是纯文本,非常适合作管道输入(Linux 管道与重定向:从文件描述符到进程替换 里的手法在这里很好用)。
几个容易踩的坑
lsblk的ROTA在虚拟机上不可信。vda 报ROTA=1不等于机械盘,TRAN列为空也是 virtio 的正常表现。- SMBIOS 是模拟的,别拿
dmidecode的频率、速度字段做性能判断。要性能就用 fio 磁盘性能测试:从顺序吞吐到 4K 随机 IOPS 的存储基准 这类实测。 - 缓存和 NUMA 是宿主机的。虚拟机看到的 L3 大小和 NUMA 节点拓扑反映宿主机,不构成你的资源配额。
dmidecode需要 root,脚本里要提权;能用/sys/devices/virtual/dmi/id/就读它。/proc/cpuinfo只反映当前 CPU。多路机器上直接cat /proc/cpuinfo会打印所有逻辑核,脚本里记得grep -m1或lscpu汇总。- 别只看一个来源。
free的free列、lsmem的向上取整、meminfo的精确 kB 值三者含义不同,报数前先确认口径。
小结
| 想干什么 | 用什么 |
|---|---|
| CPU 型号、核心拓扑、缓存、漏洞状态 | lscpu |
| 内存总量与可用量 | free -h / /proc/meminfo |
| 内存块与热插拔粒度 | lsmem |
| 块设备、大小、总线类型 | lsblk -d -o NAME,SIZE,ROTA,TYPE,TRAN,MODEL |
| 设备与驱动绑定关系 | lspci -k / lsusb |
| 网卡驱动与总线地址 | ethtool -i |
| 设备物理位置追溯 | udevadm info -q property -p /sys/block/<dev> |
| 整机身份(需 root) | dmidecode -t system,bios,processor,memory |
| 整机身份(免 root) | cat /sys/devices/virtual/dmi/id/* |
| 判断虚拟机 | systemd-detect-virt + dmesg + /proc/cpuinfo flags |
一句话总结这篇文章:Linux 给你的硬件信息来自不同源头,CPU 说的、SMBIOS 说的、设备模型说的可能互相打架——知道每个值从哪来,才知道该信哪一个。
评论 (0)
暂无评论,快来抢沙发吧!