Dosu LogoDosu Logo
Ask
Join our Discord
KubeVirtPublic
KubeVirt
DocumentsKubeVirt
VM Memory Overhead
VM Memory Overhead
Type
Topic
Status
Published
Created
Jul 20, 2026
Updated
Jul 20, 2026

VM Memory Overhead#

KubeVirt adds memory overhead on top of a VM's guest memory when sizing the virt-launcher pod. This overhead accounts for the QEMU/KVM process stack, KubeVirt daemons, page tables, video RAM, and other per-VM infrastructure. Understanding how it is calculated, applied, and exposed is essential for capacity planning, Kubernetes QoS tuning, and debugging OOMKill events.

Key source files:

  • pkg/hypervisor/kvm/hypervisorbackend.go — GetMemoryOverhead(), fixed process constants
  • pkg/virt-controller/services/renderresources.go — WithMemoryOverhead(), WithMemoryRequests(), WithAutoMemoryLimits()
  • pkg/virt-controller/services/template.go — CalculateMemoryOverhead(), pod annotation injection
  • pkg/virt-controller/watch/vmi/lifecycle.go — updateMemoryOverheadStatusFromPod(), VMI status update

Overhead Calculation#

The entry point is GetMemoryOverhead() in the KVM hypervisor backend. It computes a total overhead value by summing several components:

Fixed process overhead#

ProcessConstant
virt-launcher-monitor25 Mi
virt-launcher100 Mi
virtlogd25 Mi
virtqemud40 Mi
qemu (base, beyond guest RAM)30 Mi

These are observable RSS values rounded up for safety . The QemuOverhead constant is subject to periodic revision as QEMU grows with new virtio features and guest OS sizes increase — it was bumped from 30 Mi to 50 Mi in PR #18388 to resolve CI flakes .

Dynamic overhead components#

All computed inside GetMemoryOverhead():

  • Page tables: 1 bit per 512 bytes of guest RAM
  • vCPU tables: 8 Mi per vCPU + 8 Mi static for IOThreads
  • Video RAM: 32 Mi if AutoattachGraphicsDevice is enabled (default)
  • ARM64 UEFI pflash: +128 Mi on arm64
  • VFIO devices: +1 Gi to cover DMA-locked guest RAM + MMIO space
  • DownwardMetrics disk: +1 Mi for memory-backed emptyDir
  • Exec probes: +100 Mi base + 10 Mi per probe (virt-probe binary overhead)
  • SEV/SEV-SNP/SEV-ES: +256 Mi for encrypted memory regions
  • TPM (swtpm): +53 Mi
  • Dedicated CPU / Guaranteed QoS: +100 Mi
  • Custom reserved overhead: additive field from spec.domain.memory.reservedOverhead.addedOverhead
  • Additional ratio multiplier: an optional cluster-level ratio applied last to scale the entire overhead value

Applying overhead to the pod#

WithMemoryOverhead() in renderresources.go adds the computed overhead to the pod's memory request, and always adds it to the memory limit (even when overcommitGuestOverhead: true prevents it from being added to the request) . For hugepages VMIs, WithHugePages() routes the overhead into the ordinary memory request rather than hugepages pages.

Auto memory limits default to 2× the memory request if no explicit limit is set, controllable per-namespace via the label alpha.kubevirt.io/auto-memory-limits-ratio .

Overcommit Strategies and QoS#

KubeVirt offers three memory overcommit strategies to increase node VM density, each with a different QoS trade-off :

1. Overcommit guest overhead (overcommitGuestOverhead: true)#

Setting spec.domain.resources.overcommitGuestOverhead: true on a VMI excludes the calculated overhead from the pod request (it is still included in the limit). This reduces the per-VMI Kubernetes accounting cost. Best for short-lived or bursty VMs where temporary OOM risk is acceptable .

2. Explicit guest memory overcommit#

A VMI can be configured with a guest memory size larger than the Kubernetes memory request (e.g., spec.domain.memory.guest: 2Gi but spec.domain.resources.requests.memory: 1Gi). Kubernetes assigns the pod a Burstable QoS class, making it the first to be evicted under node memory pressure .

3. Implicit cluster-level overcommit (memoryOvercommit)#

The KubeVirt CR field spec.configuration.developerConfiguration.memoryOvercommit accepts a percentage (default 100). When set above 100, WithMemoryRequests() automatically scales down the pod memory request to (guest_memory × 100) / overcommit_percent, allowing more VMs per node without per-VMI changes .

Overcommit is only applied when all of: memory requests are not explicitly set on the VMI, guest memory or hugepages are present, and the overcommit config is not 100. Explicitly set memory requests are preserved to allow the user to achieve Guaranteed QoS .

QoS classes#

ScenarioQoS ClassEviction Priority
requests = limitsGuaranteedLast
requests < limitsBurstableFirst

For Guaranteed QoS, an extra 100 Mi is added to GetMemoryOverhead() , and sidecar containers also have their requests set equal to limits .

Reducing overhead to save memory#

Disabling the graphical device (spec.domain.devices.autoattachGraphicsDevice: false) removes the 32 Mi video RAM overhead per VMI . For high-density nodes, enabling KSM via node labels can deduplicate shared memory pages across VMs.

Overhead Visibility: VMI Status and Pod Annotation#

Feature gate#

The VmiMemoryOverheadReport feature gate (Beta) controls overhead exposure. When enabled:

  1. Pod annotation: CalculateMemoryOverhead() stores the computed value as kubevirt.io/memory-overhead-bytes on the virt-launcher pod .
  2. VMI status: updateMemoryOverheadStatusFromPod() reads the annotation and writes it to VMI.status.memory.memoryOverhead during the lifecycle reconciliation loop .

Recording the overhead on the pod at creation time (rather than recalculating it) ensures the value remains consistent across KubeVirt upgrades and cluster config changes .

Live migration#

During live migration a target virt-launcher pod is created, possibly on a node with different hardware (e.g., different arch, different enabled features). The target pod's overhead is tracked separately at VMI.status.migrationState.targetMemoryOverhead for the duration of the migration, then promoted to VMI.status.memory.memoryOverhead once migration completes .

Usage#

  • Metrics collectors and monitoring agents can read status.memory.memoryOverhead without recalculating it, getting a stable value tied to the actual running pod.
  • Schedulers and capacity planners can sum spec.domain.resources.requests.memory + status.memory.memoryOverhead to determine real node memory consumption per VMI.
  • The annotation kubevirt.io/memory-overhead-bytes on virt-launcher pods can be used for direct pod-level queries.
Documents
ACPI Management
Backup Libvirt Integration
GPU Host Device Management
Hotplug Volume Management
Install Strategy Generation
Kubernetes Dependency Management
Kubernetes JSON Patch Concurrency
KubeVirt Bridge Networking
KubeVirt Live Migration
KubeVirt VM Network Connectivity
KubeVirt Workload Update Strategy
ServiceMonitor Capability Detection
Virt-Operator Deployment Reconciliation
VM Hibernation and Memory State
VM Incremental Backup
VM Lifecycle Management
VM Memory Overhead
VM Restore Admission Validation
VM Snapshot Lifecycle
VMExport
VMI Memory Validation
VMI Network Interface Status