背景 链接到标题

PVE 虚拟机调整内存有两种常见场景:

  1. 扩容:虚拟机需要更多内存,希望不停机直接添加
  2. 宿主机压力回收:宿主机内存不足时,临时压缩虚拟机内存

传统方式需要关机修改再开机,导致服务中断。通过 Hotplug 和 Ballooning 可以解决这两个问题。

内存热添加(Hotplug) 链接到标题

原理 链接到标题

QEMU 在启动时可以预留内存槽位(slots)和最大内存上限(maxmem),运行中通过 device_add 命令插入 pc-dimm 设备来增加内存。

配置步骤 链接到标题

# 1. 启用 memory hotplug 和 numa
qm set <vmid> --hotplug "memory"
qm set <vmid> --numa 1

# 2. 首次需要 shutdown + start(让 QEMU 带上 slots/maxmem 参数)
qm shutdown <vmid>
qm start <vmid>

首次启动后 QEMU 命令行会变为类似:

-m size=1024,slots=255,maxmem=131072M

在线扩容 链接到标题

# 直接修改内存值,立即生效,无需重启
qm set <vmid> --memory 8192

QEMU 会自动创建新的 memory backend 对象并插入 pc-dimm 设备,Guest OS 识别到新的 ACPI 事件后自动 online 新增内存。

注意事项:热减不可靠 链接到标题

内存热(hot-unplug)在 QEMU/Linux 中不可靠,主要受以下限制:

  • Linux 内核限制:Linux 内核会在某些内存页上标记为不可移动(unmovable),如果这些分配恰好在要移除的 DIMM 上,内核无法 offline 该内存块。如 Proxmox 论坛所述:“if linux kernel have set some memory pages as unmovable, it’s impossible to unplug the dimm”1
  • 随机失败:热减的成败取决于 Guest OS 当前的内存分布,具有随机性。“it’s a linux limitation, it’s really random working/non working (not working with windows too)”2
  • 生产环境高负载时几乎必然失败:数据库等应用会分配大量不可移动页面,热减时会出现 dimm38: error unplug memory module 错误3
  • PVE 曾有 Bug:旧版 foreach_reverse_dimm 实现存在逻辑错误,热减后内存计数不准确4
  • movable_node 方案有副作用:虽然可以让更多内存成为可移动区域,但会导致 Normal zone 内存不足,触发 OOM killer 误杀进程5

因此,减小内存的推荐做法是关机修改再开机,不要依赖热减。

内存动态回收(Ballooning) 链接到标题

原理 链接到标题

PVE 创建的虚拟机默认带有 virtio-balloon-pci 设备。pvestatd 守护进程监控宿主机内存压力:

  • 宿主机内存吃紧 → inflate balloon(压缩虚拟机内存)
  • 宿主机内存充裕 → deflate balloon(自动归还给虚拟机)

配置弹性区间 链接到标题

设置 balloon 下限,为自动缩放留出空间:

# 虚拟机 8GB,下限 4GB,PVE 可在 4G~8G 之间自动平衡
qm set <vmid> --memory 8192 --balloon 4096

查看运行中的 balloon 状态:

qm monitor <vmid>
# 在 monitor 中输入:
info balloon

输出示例:

balloon: actual=8192 max_mem=8192 total_mem=7901

手动临时调整 链接到标题

如果需要在宿主机压力较大时立即回收,可通过 QEMU monitor 手动操作:

echo "balloon 4096" | qm monitor <vmid>

注意:这只是临时生效,balloon 配置项在 PVE 中定义的是最小值下限,实际 balloon 由 pvestatd 自动管理。

完整配置示例 链接到标题

以一台 4GB 的虚拟机为例,配置热添加和弹性回收:

# 启用 hotplug 和 numa
qm set 6000 --hotplug "memory"
qm set 6000 --numa 1

# 第一次:关机关机加载新配置
qm shutdown 6000
qm start 6000

# 在线扩容到 6GB
qm set 6000 --memory 6144

# 设置 balloon 下限 4GB,保留弹性空间
qm set 6000 --balloon 4096

总结 链接到标题

  • Hotplug:解决在线扩容问题,配置简单可靠(仅限增大)
  • Ballooning:解决宿主机压力调度问题,自动弹性伸缩
  • 热减不可靠:缩小内存请关机操作,不要依赖 hot-unplug
  • 首次配置后,后续调整内存均可在线完成

  1. Proxmox Support Forum — Debian RAM hot-unplug error: The module couldn’t be unplugged, most likely because the guest kernel was unable to relocate memory ↩︎

  2. Proxmox Support Forum — Hotplug memory downgrade is not working: it’s a linux limitation, it’s really random working/non working ↩︎

  3. Proxmox Support Forum — TASK ERROR: dimm38: error unplug memory module: error unplug memory module in production ↩︎

  4. Proxmox qemu-server commit — memory: don’t use foreach_reversedimm for unplug: fix existing bug with reverse dimm iteration ↩︎

  5. PVE-User mailing list — Memory Hotplug Woes: movable_node leads to OOM kills with postgresql ↩︎