A virtual machine (VM) is an execution environment that presents software with a computer or an abstract machine rather than requiring it to interact directly with the underlying hardware. A system virtual machine provides the resources needed to run an entire operating system, while a process virtual machine provides an environment for executing an individual program. These two uses share the principle of implementing a machine interface through software, often with hardware assistance, but differ in their scope and purpose.
System virtual machines allow multiple operating systems to share a physical computer under the control of a hypervisor, also called a virtual machine monitor. They support workload isolation, hardware consolidation, and the movement or replication of computing environments, making them an important component of data centers and cloud computing. Process virtual machines, including language runtimes such as the Java Virtual Machine, support portable program execution and may provide services such as automatic memory management and runtime verification.
Virtual machines developed from mainframe time-sharing and experimental operating systems in the 1960s into widely used infrastructure and programming-language technologies. Their design involves trade-offs among compatibility, performance, resource sharing, and security. Understanding these trade-offs requires distinguishing virtual machines from related technologies such as hardware emulators, operating-system containers, and other forms of software isolation.
Machine Interfaces and Categories
A virtual machine (VM) is an execution environment that implements a machine interface: a defined set of instructions, resources, and operations through which software uses a computing machine. Software targeting that interface can execute without directly controlling the corresponding physical resources. The environment is distinct from its implementation, such as a hypervisor or language runtime; its configuration, such as an assigned processor count and memory size; and its stored image, such as a file containing a bootable disk. One implementation can run many VM instances, and one disk image can supply the initial contents for several instances. An image alone is not an executing machine, and a disk image need not contain the memory and processor state required to resume a suspended instance.
A system virtual machine presents a hardware-level environment sufficient to run a guest operating system. It supplies virtual processors, memory, and the device and boot interfaces required by the selected platform. For example, a VM configured with four virtual processors and 8 GiB of memory presents those resources to its guest; that configuration does not necessarily reserve four physical processor cores or 8 GiB of dedicated physical memory. The guest is the software executing within the virtual environment, particularly its operating system and applications. The host is the environment providing the virtualization facilities; depending on the design, this includes a host operating system or a hypervisor running directly on hardware. The physical machine is the underlying computer, including its actual processors, memory, and peripherals. A system VM can boot, run multiple applications, and remain active independently of any one guest application.
A process virtual machine, also called an application virtual machine, principally provides an execution environment for a program rather than a complete guest operating system. Its interface may resemble an operating-system process environment or an abstract machine defined for compiled language instructions. The Java Virtual Machine, for example, defines class-file structures, instructions, and execution rules that implementations support on different host platforms. One JVM instance can execute many classes and threads without providing a separate guest kernel. Such an environment is ordinarily created to execute an application and terminates when that execution ends, whereas a system VM’s lifetime follows the guest machine’s boot and shutdown cycle. This distinction concerns the abstraction presented, not simply the number of applications or threads running.
These categories can be understood through the interface boundary being implemented. An instruction-set architecture (ISA), such as x86-64 or AArch64, defines processor instructions and architectural state; its system-level facilities also support operating-system functions such as interrupt handling and privileged execution. An application binary interface (ABI) specifies binary conventions, including register use, calling conventions, data layout, and interaction with operating-system services. An environment supporting existing native application binaries may therefore need to reproduce both user-level instructions and relevant operating-system interfaces without booting an entire guest operating system. Language-level instruction sets establish another boundary: Java bytecode, for example, describes operations on abstract runtime values rather than instructions for a particular physical processor. Whether instructions are interpreted, translated, or executed directly is an implementation choice, not the defining basis of these categories.
Virtual memory alone does not constitute a virtual machine. It maps addresses used by software to backing memory and can give each process a separate address space, but it does not by itself implement the processor, device, operating-system, or language-level interface needed for a distinct machine execution environment. An ordinary process using virtual memory still executes under its operating system’s native process model. Conversely, a VM may use virtual memory internally while also providing a broader machine interface.
Historical Development
System virtualization developed at IBM’s Cambridge Scientific Center in the 1960s as part of research into time-sharing: allowing several users to interact with one expensive computer rather than submitting jobs solely for sequential batch processing. Work on the experimental CP-40 system began in 1964 under Robert Creasy. Running on a modified System/360 Model 40, CP-40 provided multiple isolated virtual machines, each presenting an interface on which an operating system could execute. Its Control Program allocated physical resources, while the Cambridge Monitor System supplied an interactive, single-user environment inside a virtual machine. This design separated the problem of sharing the physical computer from that of providing each user’s programming environment.
CP-40 became operational in 1967. Its successor, CP-67, adapted the approach to the IBM System/360 Model 67, whose dynamic address translation hardware supported the memory mappings needed for virtual-machine operation. CP-67 entered use in 1967, and CP-67/CMS was distributed more widely in 1968. Unlike time-sharing systems that placed all users within one operating-system instance, CP-67 could run separate operating systems concurrently, including systems being tested or modified. Interactive computing and operating-system development thus reinforced one another: developers could experiment in one virtual machine without taking exclusive possession of the physical mainframe.
IBM announced VM/370 in 1972 for the System/370 family, establishing virtualization as a supported mainframe product rather than only a research facility. Its two principal components preserved the earlier division of responsibilities. The Control Program, or CP, managed virtual processors, memory, and devices; the Conversational Monitor System, or CMS, provided an interactive operating environment within individual virtual machines. CMS retained the initials of the earlier Cambridge Monitor System but changed their expansion. Users could work in separate CMS instances while other guests ran different operating systems. The CP/CMS model demonstrated how machine compatibility, resource sharing, and interactive use could coexist, and its architectural lineage continued in later IBM VM products.
A parallel tradition used abstract machines to make programs portable rather than to reproduce a complete physical computer. At the University of California, San Diego, Kenneth Bowles led development of the UCSD Pascal system in the mid-1970s. The UCSD p-System compiled programs into p-code, which an implementation of an intermediate machine could execute on different computers. Sun Microsystems’ Java platform, introduced in 1995, brought a related portability model to a much wider audience: Java compilers produced class files containing instructions for the Java Virtual Machine, with execution supplied by a platform-specific runtime. Microsoft’s Common Language Infrastructure standardized a comparable foundation for multiple languages; its first ECMA standard appeared in 2001, followed by the .NET Framework in 2002. These systems made an intermediate instruction set and associated runtime services central to application deployment, although their machines served programs rather than complete guest operating systems.
Virtualization expanded onto commodity x86 computers through several distinct developments. VMware released VMware Workstation in 1999, allowing multiple operating systems to run on a desktop computer. Early x86 processors presented obstacles to straightforward virtualization because some sensitive instructions did not trap when executed without full privilege; VMware combined direct execution with binary translation to handle problematic operating-system code. Xen, released in 2003 by a University of Cambridge research team, initially emphasized paravirtualization: guest kernels were modified to cooperate explicitly with the hypervisor. Intel VT-x, introduced in 2005, and AMD-V, introduced in 2006, subsequently provided processor mechanisms for hardware-assisted virtualization, making unmodified guests easier to support.
Kernel-based Virtual Machine, or KVM, entered the mainline Linux kernel in version 2.6.20 in 2007, using hardware virtualization extensions and Linux’s existing scheduling and memory-management facilities. Together, these developments made virtual-machine hosting practical across increasingly widespread server hardware. They also supplied an important foundation for commercial cloud computing: Amazon EC2, launched in beta in 2006, initially used Xen to provide remotely provisioned computing instances. Virtualization connected established resource-sharing techniques with automated provisioning and large-scale data-center operation.
Hypervisor Architecture and Virtualization Theory
Gerald J. Popek and Robert P. Goldberg’s 1974 paper, Formal Requirements for Virtualizable Third Generation Architectures, characterized a virtual machine monitor, or hypervisor, through three properties. Equivalence requires a program running under the monitor to behave essentially as it would on the original machine, apart from permitted differences arising from timing and resource availability. Resource control requires the monitor to retain ultimate control over machine resources: a guest cannot independently obtain resources not allocated to it. Efficiency requires a statistically dominant subset of virtual-processor instructions to execute directly on the physical processor, without monitor intervention. This is a structural criterion, not a numerical guarantee of low overhead. Their formal model concerned conventional third-generation computers with supervisor and user execution modes and a relocation-and-bounds memory model; its conclusions depend on those architectural assumptions rather than applying unchanged to every modern processor.
The theory distinguishes privileged instructions, which trap when executed in user mode but not in supervisor mode, from sensitive instructions. Control-sensitive instructions attempt to change resource configuration; behavior-sensitive instructions produce results that depend on that configuration or on execution mode. A central sufficient condition for constructing a monitor is that every sensitive instruction also be privileged. The guest operating system can then execute outside supervisor mode: ordinary instructions run directly, while sensitive operations trap to the monitor, which reproduces their effect on virtual rather than physical machine state. This is the basis of trap-and-emulate virtualization. Some pre-extension x86 instructions violated the condition. For example, under relevant protected-mode privilege settings, POPF could leave the interrupt-enable flag unchanged without trapping, rather than performing the change expected by a guest kernel. Such cases obstructed straightforward trap-and-emulate virtualization; they did not establish that virtualization by other techniques was impossible.
The distinction between type 1 and type 2 hypervisors describes their relationship to the underlying platform. A type 1, or bare-metal, hypervisor controls hardware beneath guest operating systems; Xen and VMware ESXi are familiar examples. A type 2, or hosted, implementation relies on a conventional host operating system for services such as device access, scheduling, and memory allocation, as in a typical Oracle VirtualBox desktop installation. Real architectures complicate this binary classification. Xen delegates substantial management and device-service responsibilities to a privileged domain, commonly called Domain 0, without making that domain the hypervisor itself. KVM places virtualization support within the Linux kernel and commonly uses QEMU in user space for device models. Thus, the presence of a general-purpose kernel or user-space device process alone does not settle classification; descriptions should identify which components control processor execution, memory protection, and devices.
Full virtualization, paravirtualization, and hardware-assisted virtualization describe different design dimensions, not mutually exclusive product categories. Full virtualization presents a sufficiently complete hardware interface for an operating system to run without virtualization-specific modification. Paravirtualization instead exposes interfaces that a virtualization-aware guest uses deliberately, often through hypercalls requesting privileged services. Hardware assistance supplies processor mechanisms that enable controlled guest execution and interception of selected operations. Consequently, an unmodified guest kernel can use hardware-assisted execution while optional paravirtualized drivers accelerate storage or networking. Conversely, early x86 products combined direct execution with software translation to support full virtualization without the later processor extensions.
Execution mechanisms must also be distinguished from management components. The hypervisor’s core mechanisms establish guest execution contexts, enforce resource ownership, and handle intercepted events. Device backends and privileged service domains may perform additional work on its behalf. Management software creates and configures guests, assigns resources, and requests lifecycle operations through control interfaces; a graphical console or orchestration service does not itself execute guest instructions merely because it administers them. These roles can reside in separate processes, kernels, or machines, so an architectural description must distinguish the complete virtualization platform from its execution-control component.
Processor Execution and Hardware Assistance
A virtual CPU (vCPU) represents the architectural state of a processor visible to a guest: general-purpose registers, an instruction pointer, status flags, control registers, and, where exposed, floating-point and vector registers. Some state resides in hardware while the guest executes; other state is maintained in hypervisor data structures. A hypervisor schedules runnable vCPUs onto physical CPUs, saving and restoring state when execution switches. A VM with four vCPUs therefore need not occupy four physical cores continuously. Guest execution alternates with hypervisor handling of selected events, such as intercepted instructions, certain exceptions, and accesses to virtual hardware. Ordinary guest instructions can execute directly without invoking the hypervisor.
In trap-and-emulate execution, an operation that the guest cannot perform directly causes a processor trap; the hypervisor examines the operation, reproduces its effect on virtual processor state, and resumes execution. Historically, x86 complicated this approach because some sensitive instructions behaved differently at reduced privilege without trapping. Software virtualization systems addressed this with dynamic binary translation: they inspected guest instruction blocks, replaced problematic operations with controlled sequences, and cached translated blocks for reuse. VMware’s early x86 implementations combined translated guest kernel execution with direct execution of much application code. Translation need not rewrite every instruction, and its correctness depends on preserving architectural effects, including exceptions and changes to executable code.
Intel VT-x, first shipped in processors in 2005, and AMD-V, introduced in 2006, added explicit hardware support for guest execution. Intel distinguishes VMX root operation, normally used by the hypervisor, from VMX non-root operation, used by guests; both retain the conventional x86 privilege levels, allowing a guest kernel to run at ring 0 without controlling the host. A virtual-machine control structure (VMCS) records guest state, host state, and execution controls. VM entry starts or resumes guest execution, while a VM exit transfers control to the hypervisor and records why execution stopped. AMD provides corresponding mechanisms using the virtual-machine control block (VMCB) and the VMRUN instruction. Configurable intercepts allow many operations to proceed directly while routing selected operations, such as particular control-register accesses, to the hypervisor.
Arm introduced virtualization extensions in Armv7-A; AArch64 provides exception level EL2 for hypervisor execution, with a conventional guest kernel running at EL1 and applications at EL0. Traps and exception returns provide transitions between guest and hypervisor execution, although their terminology and state structures differ from x86 VM entries and exits. Interrupt delivery also requires virtualization: a guest must observe interrupts according to its own interrupt-controller state, masking rules, and processor priority. Hypervisors can arrange injection when a vCPU is ready to accept an interrupt. Hardware facilities, including Intel APIC virtualization and Arm’s Generic Interrupt Controller virtualization support, reduce software intervention for supported interrupt operations; they do not eliminate all exits or scheduling work.
Cross-architecture execution requires implementing a different instruction-set architecture, rather than merely controlling access to the host processor. An interpreter can decode and execute guest instructions individually, while a translator converts guest instruction blocks into host instructions. QEMU’s Tiny Code Generator, for example, supports executing Arm software on an x86 host through translation. On compatible architectures, QEMU can instead use Linux KVM to execute guest instructions with hardware acceleration. Thus emulation and same-architecture virtualization are not mutually exclusive techniques: a system may execute its guest CPU directly while emulating peripheral devices, or translate a foreign CPU while retaining similar virtual-device infrastructure.
In nested virtualization, an outer hypervisor, conventionally called L0, runs a guest hypervisor, L1, which runs an inner guest, L2. L0 must expose a virtual implementation of the virtualization extensions to L1 while retaining ultimate control of physical execution. For example, L1’s requested interception controls must be combined with L0’s requirements, and exits from L2 must be handled by L0 or reflected to L1 as appropriate. Virtualization control structures, interrupt state, and address-translation controls require additional bookkeeping. Hardware and software optimizations can reduce these costs, but exposing ordinary CPU instructions to a guest does not by itself make nested virtualization available.
Memory Virtualization
A system virtual machine normally exposes three address spaces. An application uses guest virtual addresses, which the guest operating system maps to guest physical addresses through its page tables. The hypervisor separately maps guest physical addresses to host physical addresses, identifying actual machine memory. Conceptually, translation is therefore . On a machine running without a hypervisor, the operating system’s page tables ordinarily map virtual addresses directly to machine physical addresses. Inside a VM, “physical” instead describes the guest’s view: adjacent guest physical pages need not occupy adjacent host frames, and some configured guest memory may have no host frame backing it until accessed. In hosted implementations, a user-space virtual-machine process may also have host virtual mappings of guest RAM; these are distinct from the guest’s address spaces.
Shadow page tables combine the two mappings in software. The guest maintains tables describing GVA-to-GPA translation, while the hypervisor constructs hardware-consumable shadow tables mapping GVA directly to HPA. Guest page-table changes must be detected and reflected in the shadows, commonly through write protection and trapped writes, supplemented by handling address-space changes and invalidations. This avoids a hardware second-stage walk but makes frequent mapping changes expensive. Hardware-assisted second-stage translation instead lets the processor walk guest-managed tables and then translate their guest physical addresses through hypervisor-managed tables. Intel calls this Extended Page Tables (EPT); AMD uses nested paging, also called Rapid Virtualization Indexing; Arm provides stage-2 translation, following the guest’s stage-1 translation. These mechanisms distinguish a missing or prohibited guest mapping from a second-stage fault requiring hypervisor intervention. They reduce software synchronization of guest page tables, although a translation-cache miss can require multiple dependent memory accesses through both sets of tables.
Configured memory capacity does not necessarily equal reserved physical memory. With demand allocation, a hypervisor supplies backing pages as the guest touches memory; untouched regions need not consume equivalent host RAM. Ballooning uses a cooperating guest driver: when asked to inflate, it allocates and retains guest pages, reports them to the hypervisor, and permits their host backing to be reclaimed. The guest operating system may respond by reclaiming caches or paging other contents to its own storage. Deflating the balloon returns capacity to guest use. Host swapping, by contrast, moves guest-memory contents to host-managed storage without relying on guest memory-management decisions. The two mechanisms can interact poorly if both host and guest page data out. Reservations, limits, and overcommit policies therefore determine how much physical backing is guaranteed, independently of the RAM size visible inside the VM.
Page sharing reduces consumption by identifying pages with identical contents and mapping them to one host frame. Shared mappings are typically read-only; a write triggers allocation of a private copy through copy-on-write. Linux Kernel Samepage Merging, merged in Linux 2.6.32 in 2009, provides this mechanism for eligible memory regions, including memory used by KVM guests. Sharing requires scanning and comparison work, and savings depend on actual content rather than merely running identical operating systems. Because cross-guest sharing can also expose information through timing differences, implementations may restrict sharing or leave it disabled.
The translation lookaside buffer (TLB) caches translations, reducing repeated page-table walks; virtualization-capable processors can cache combined translations and use address-space identifiers to limit unnecessary flushing. Mapping changes still require appropriate invalidation. Large pages increase the address range covered by each cached translation: an x86 2 MiB page covers 512 times as much memory as a 4 KiB page. However, large guest pages alone do not guarantee equally large combined mappings; host backing, alignment, and second-stage mappings also matter. On non-uniform memory access (NUMA) systems, memory placement relative to physical processors adds another constraint. A guest may see virtual NUMA nodes, but locality depends on where its virtual CPUs execute and where their memory is actually allocated. Migration between host nodes or uneven allocation can turn accesses intended to be local into higher-latency remote accesses.
Virtual Devices, Storage, and Networking
An emulated device reproduces a hardware interface, such as an Intel e1000 network adapter or an IDE disk controller, so that a guest can use an existing hardware driver. The guest writes device registers and submits commands; a host-side device model interprets these operations, accesses storage or networking services, and presents completion status and interrupts. A paravirtualized interface instead exposes a contract designed for virtualization. With virtio, the guest driver places buffer descriptors in shared-memory queues, while a backend processes requests and reports completions. Backends may run in a user-space device model, a host kernel, or a dedicated process. Batching requests and suppressing unnecessary notifications reduce transitions between guest and host. Direct assignment moves ordinary device operations out of this software path: a guest driver controls assigned hardware, although host software still configures access, interrupts, and device ownership.
An input–output memory management unit (IOMMU) translates device-generated direct memory access (DMA) addresses and restricts which memory regions a device can access. This is distinct from the processor’s translation of guest memory accesses. PCI passthrough assigns a physical PCI function to a guest; safe isolation also depends on the platform’s device grouping, reset facilities, and interrupt-remapping support. Single Root I/O Virtualization (SR-IOV) lets a capable PCIe device expose multiple virtual functions under a physical function managed by the host. Guests can receive separate virtual functions, each with device-specific queues and resources, without receiving the entire adapter. Mediated access takes another approach: host software presents controlled portions of an accelerator, such as a GPU, to guests and coordinates access to shared hardware. Supported operations, isolation mechanisms, and scheduling policies depend on the device and implementation.
A virtual disk presents a block-addressed device to the guest, but its backing storage may be a host file, a logical volume, or a remote block device. Sparse allocation reserves logical capacity without immediately allocating physical storage for every block; host storage is consumed as previously unallocated regions are written. A copy-on-write image can read unchanged blocks from a backing image while recording modifications in a separate layer. A read may therefore require consulting several layers, whereas a write allocates space in the writable layer. Disk-image formats and guest filesystems occupy different abstraction levels: a qcow2 image describes block mappings and image metadata, while those blocks might contain a partition table and an ext4 or NTFS filesystem. The host need not understand that filesystem to service block requests. Discard commands can communicate that blocks are no longer needed, although reclaiming physical space depends on support throughout the storage stack.
A virtual network interface similarly separates the guest-visible adapter from packet forwarding. For example, a guest virtio driver submits an Ethernet frame through a transmit queue; the backend delivers it to a host networking endpoint, often a TAP interface or an in-kernel switching path. A virtual switch then forwards the frame to another guest, a host interface, or a physical uplink. Bridging places interfaces in a common layer-2 forwarding domain, whereas routing transfers packets between IP networks. Network address translation rewrites addresses and, commonly, transport-layer ports, allowing guests with private addresses to communicate through a host’s external address. Overlay networks add encapsulation between hosts: VXLAN, for example, carries Ethernet frames inside UDP packets and identifies logical networks using a 24-bit network identifier. External traffic must eventually leave the overlay through an appropriate physical interface or gateway.
Virtual clocks and firmware complete interfaces that processor instruction execution alone cannot supply. Guests may expect legacy timer devices, local APIC timers, or a paravirtual clock that derives time from a processor counter and host-provided conversion parameters. A timer deadline can expire while a virtual CPU is descheduled; the hypervisor must arrange a pending interrupt when that CPU can run again. Clock offsets and scaling help preserve guest-visible time across scheduling interruptions and supported migrations. Firmware interfaces also shape discovery and boot: BIOS or UEFI initializes the virtual platform, ACPI tables describe devices and power-management facilities, and interrupt-controller descriptions tell the guest how interrupts are routed. Compatibility therefore depends on coherent register behavior, DMA, interrupts, timing, and firmware descriptions—not merely on executing the guest’s instruction set.
Process Virtual Machines and Managed Runtimes
A process virtual machine supplies an execution environment for a program rather than virtual hardware for a complete guest operating system. Its intermediate instruction set separates program representation from the processor instructions ultimately executed. In the Java toolchain, javac normally translates source files into class files containing bytecode, symbolic references, and metadata; a Java Virtual Machine (JVM) loads and executes these files. The JVM specification defines the class-file format and instruction semantics without requiring a particular execution strategy. In Microsoft’s .NET toolchain, compilers for languages such as C# produce assemblies containing Common Intermediate Language (CIL) instructions and metadata. The Common Language Runtime (CLR) uses this information to resolve types, manage execution, and provide runtime services. These intermediate formats also support multiple source languages: Java, Kotlin, and Scala can target the JVM, while C#, Visual Basic, and F# can target .NET.
The JVM and CIL use predominantly stack-based instruction sets: instructions obtain operands from an evaluation stack rather than naming general-purpose processor registers. For example, JVM instructions iload_0, iload_1, and iadd load two integer local variables and replace them on the operand stack with their sum. A JVM method invocation creates a frame containing local variables, an operand stack, and information used for dynamic linking. Register-based virtual instruction sets instead name virtual registers explicitly; Android’s Dalvik executable format uses this design, which remains relevant to its successor runtime, ART. Neither design dictates how values occupy physical registers after compilation. Exception handling uses metadata identifying protected instruction ranges and handlers; when no matching handler exists in the current invocation, execution unwinds through callers. Runtime linkage resolves symbolic names to types, fields, and methods, sometimes when first used, and can fail with a linkage error even after source compilation has succeeded.
Interpretation executes intermediate instructions through a software dispatch mechanism, whereas just-in-time (JIT) compilation translates methods or code regions into native instructions during execution. Ahead-of-time (AOT) compilation performs translation before execution, potentially reducing startup work but changing the available optimization information and deployment constraints. Implementations often combine these strategies. OpenJDK’s HotSpot can interpret initially and use tiered compilation, collecting execution counts and type profiles before applying more expensive optimizations. Profile-guided inlining may assume that a call usually targets one implementation; if a supporting assumption becomes invalid, deoptimization can reconstruct interpreter frames from compiled state and resume execution less optimistically. These mechanisms are implementation features, not requirements of every JVM. In .NET, tiered compilation and dynamic profile-guided optimization can likewise refine frequently executed code; ReadyToRun images contain precompiled code that can coexist with JIT compilation, while Native AOT uses a different deployment model without a runtime JIT compiler.
Managed runtimes also coordinate allocation, garbage collection, type checks, synchronization, and class or assembly loading. Garbage collectors determine which objects remain reachable and reclaim storage for others; moving collectors additionally update references when relocating objects. Bytecode verification checks structural and type-related properties before execution, rather than proving arbitrary program correctness. JVM checks include compatible operand-stack states at control-flow joins and valid uses of typed instructions. CIL likewise has verification rules, although not all executable CIL is verifiable, and unsafe code and native interoperability require additional distinctions. Such guarantees do not establish an operating-system security boundary: managed code can still consume resources, access permitted files, or invoke native functions with the process’s privileges.
Portability therefore depends on more than a shared instruction format. A class-file version or required library API may be unsupported by an older Java runtime; .NET applications similarly depend on compatible runtime and library capabilities. Java Native Interface calls, .NET platform invocation, and other foreign-function interfaces introduce dependencies on native libraries, processor architectures, and calling conventions. Filesystem conventions, available graphical services, and platform-specific APIs can also affect behavior. Moreover, a language interpreter need not implement a separately specified virtual machine: an implementation may evaluate syntax trees directly or use internal bytecode whose format is not a stable portability contract.
Images, State, and Lifecycle Management
Creating a system VM establishes both a virtual-hardware configuration and the storage from which a guest operating system will boot. Installation media allow the guest installer to partition a virtual disk and install software; templates instead supply an already prepared disk image, often customized at first boot with credentials, network settings, and a machine identity. Configuration specifies virtual CPU count, memory, firmware, disk controllers, and network interfaces. Starting the VM initializes these devices and enters its firmware or boot sequence. Suspension preserves execution state, including virtual CPU registers, memory, and supported device state, either in host memory or in a saved-state file. Resumption continues that execution rather than rebooting. Powering off ends execution but ordinarily retains persistent disks; deleting a VM and deleting its associated storage are separate management operations.
A disk snapshot records a recoverable point in virtual storage history, not necessarily a complete running machine. With copy-on-write storage, subsequent writes enter a new layer while unchanged blocks remain in earlier layers. Deleting or consolidating a snapshot can therefore require merging blocks, rather than simply removing an independent file. A memory-inclusive snapshot additionally captures RAM and execution state, allowing restoration of an active session. A full clone copies the required storage into an independent instance; a linked clone retains dependencies on a parent image or snapshot. A backup preserves recoverable data under a separate retention and failure-protection arrangement. A snapshot on the same storage system is not, by itself, an independent backup: loss of its base image or storage can make the entire chain unusable.
Captured state also differs in consistency. A crash-consistent disk snapshot resembles the persistent storage left after sudden power loss: writes held only in guest memory are absent, and filesystems or databases may require recovery. Application-consistent capture coordinates applications, flushes relevant buffers, and establishes a recoverable transaction boundary before taking the snapshot. For example, Microsoft Volume Shadow Copy Service coordinates writers for participating applications, while guest-agent interfaces can request filesystem freezing in supported guests. Freezing a filesystem alone does not establish consistency across every application or external service. Restoring a VM also cannot roll back a payment already accepted by another server or a message already consumed elsewhere; such dependencies require coordination beyond the captured machine.
Cold migration moves a VM while it is shut down, transferring its configuration and required storage before booting at the destination. Live migration instead transfers a running machine with a limited interruption. In pre-copy migration, memory is copied while the source continues executing; dirty-page tracking identifies pages modified during copying for subsequent rounds. A final pause transfers remaining pages, processor registers, and device state before execution resumes at the destination. Rapidly changing memory can prevent convergence. Post-copy migration transfers enough state to start the destination first, then obtains missing memory pages from the source, including through fault-triggered requests. This avoids repeatedly copying dirty pages but makes execution dependent on completing memory transfer. Both methods require shared storage or a coordinated transfer of disk contents, as well as network arrangements that preserve guest connectivity.
Checkpointing records recoverable execution state, while replication maintains copies of storage or machine state on another system. Asynchronous replication can leave a recovery point behind the latest completed work. Restart-based high availability detects a failed host and boots affected VMs elsewhere from accessible persistent disks; guest memory is generally lost, and applications undergo restart recovery. Continuous fault-tolerance systems instead maintain closely synchronized execution or state on a secondary machine, aiming to continue without a guest reboot. Restoring or migrating captured state requires compatible processor features, virtual-device models, firmware, and hypervisor state formats. Directly assigned devices can impose additional restrictions because their internal state may not be exportable or reproducible on another host.
Deployment and Uses
Server consolidation places workloads formerly assigned to separate physical servers into separate VMs on shared hosts in a data center. Each guest retains its own operating system and software configuration, while the virtualization platform allocates processor time, memory, storage, and network connectivity. In infrastructure as a service (IaaS), these resources become provisionable instances: Amazon Elastic Compute Cloud, introduced in beta in 2006, is an early commercial example. A provisioning request typically specifies an image, instance size, storage volumes, network attachments, and access credentials. Cloud management software selects a suitable host, creates the required resources, and coordinates startup through hypervisor and infrastructure APIs. OpenStack, launched in 2010, separates these responsibilities among services including Nova for compute, Neutron for networking, and Cinder for block storage. Resource sizing specifies quantities such as virtual CPUs and memory, but an allocation is not necessarily a reservation of dedicated physical hardware.
Development and testing systems use VMs to separate incompatible dependencies and repeatedly construct known software environments. An automated build worker can start from a versioned image, obtain source code, compile and test it, export results, and then be discarded. This limits contamination from previous jobs, although network services and externally downloaded dependencies can still change. Operating-system compatibility testing can run the same application against distinct releases of Windows or Linux, with each VM preserving its own libraries, registry or configuration files, and installation history. Templates and configuration automation support reproducibility, but an image alone does not record every relevant input: compiler versions, package repositories, external databases, and processor-dependent behavior may also matter. Tests involving physical devices or precise timing may require hardware that a virtual test environment does not reproduce.
Desktop virtualization separates the user’s display and input devices from the machine executing desktop applications. In virtual desktop infrastructure (VDI), a connection broker assigns a user to a desktop VM, and a remote-display protocol transports screen updates, keyboard events, and pointer input. Persistent desktops retain user-specific machine state; nonpersistent pools can replace desktops with instances derived from a common image, while storing user profiles separately. A remotely accessed desktop is not necessarily a VM: Microsoft Remote Desktop Services can provide multiple sessions within one server operating-system instance, whereas a VM-hosted desktop has its own guest operating system. Conversely, a desktop VM may run locally on a personal computer without any remote-display connection. These distinctions affect software compatibility, administration, and resource accounting.
Legacy application hosting retains an older operating system and its dependencies when moving the application to a current platform would require substantial changes. Historical environments also support digital preservation and teaching: students can examine obsolete interfaces or network configurations without replacing their workstation’s operating system. The Internet Archive’s Windows 3.1 browser collection, introduced in 2016, illustrates delivery of historical software through emulated computer environments. Such examples may require cross-architecture emulation rather than ordinary same-architecture virtualization. Preserving a disk image does not guarantee complete functionality: applications may depend on unavailable license servers, hardware dongles, specialized peripherals, or external services. Reproducing the original environment also differs from preserving the original physical machine’s timing and device behavior.
Virtual network appliances package functions such as routing, firewalling, load balancing, and virtual private network termination as deployable software images. Traffic enters through virtual network interfaces and passes through the appliance’s guest networking stack before being forwarded or filtered. Network function virtualization (NFV), promoted in a 2012 white paper by telecommunications operators and subsequently developed through ETSI specifications, applies this approach to functions previously commonly delivered in dedicated equipment. Management and orchestration systems coordinate deployment, scaling, connectivity, and recovery of virtualized network functions. A service chain can direct traffic through a virtual router, firewall, and other functions in a specified order. Packet-processing capacity depends on interface implementation, processor allocation, and acceleration facilities; replacing a physical appliance with a VM does not by itself preserve throughput or latency.
Isolation and Security Boundaries
A system VM’s security boundary separates guest-controlled execution from the hypervisor, other guests, and host resources. The threat model commonly assumes that an attacker can obtain administrator privileges inside a guest and issue arbitrary instructions and device requests, but must not thereby control the host. In conventional virtualization, the trusted computing base includes the hypervisor and any components whose compromise can defeat this separation: host-kernel facilities, privileged device backends, management services, and relevant firmware. Its extent depends on architecture; a device emulator confined to an unprivileged process has different authority from one running with unrestricted host access. Management interfaces form a separate control boundary: permission to attach disks, inspect memory, replace boot images, or access a VM console can bypass protections enforced inside the guest.
A VM escape occurs when guest-originated activity breaches the intended isolation boundary, potentially enabling execution in a host process or control over host resources. Device emulation exposes parsers, queues, registers, and state machines to untrusted guest input; errors in bounds checking or object lifetime can turn these interfaces into attack paths. VENOM, disclosed in 2015 as CVE-2015-3456, was a buffer-overflow vulnerability in QEMU’s virtual floppy-disk controller that affected multiple virtualization products using that device model. Guest integration features—including shared folders, clipboard synchronization, and host–guest communication agents—create additional interfaces beyond virtual hardware. Shared storage and networking backends also matter: compromising a service used by several guests can cross tenant boundaries even without compromising the processor-virtualization code. Process isolation, restricted privileges, and sandboxing can limit the consequences of a backend vulnerability, but do not establish that its interface is vulnerability-free.
Cross-VM side-channel attacks exploit observable effects of shared resources rather than authorized access to another guest’s address space. For example, an attacker can prime processor-cache sets, allow a victim to execute, and measure subsequent access times to infer which cache resources the victim used. In 2009, Thomas Ristenpart and colleagues demonstrated co-residency and cross-VM information leakage in Amazon EC2, illustrating how placement and shared hardware could affect cloud isolation. Speculative-execution vulnerabilities disclosed in 2018 further exposed the importance of microarchitectural state. Such leakage is distinct from directly mapping another VM’s memory or reading its disk: architectural access checks may remain intact while timing observations reveal information. Exposure and mitigation depend on processor design, resource sharing, software behavior, and scheduling; memory separation alone does not remove these channels.
Stored and transferred VM state creates security boundaries outside execution. Disk images may contain credentials, private keys, application data, or deleted information retained in older copy-on-write layers. Memory snapshots can additionally capture plaintext secrets and active session state that were never written to disk. Access controls and encryption therefore apply independently to image repositories, snapshot stores, backups, and their encryption keys. Live migration transfers execution state, including memory pages, so its endpoints require authentication and its transport requires confidentiality and integrity protection across untrusted networks. Management credentials are especially consequential because control-plane privileges can permit image export or console access regardless of guest login restrictions. Restoring an old snapshot may also restore outdated credentials or security-sensitive state.
Secure Boot, virtual trusted platform modules, and confidential computing address different threats. UEFI Secure Boot checks signatures on boot components against configured trust databases; it does not establish that signed software is free of vulnerabilities. A virtual trusted platform module provides facilities such as measured-boot registers, key protection, and sealing to selected platform measurements, but its guarantees depend on how its implementation and stored state are protected. AMD SEV-SNP and Intel TDX extend protection toward threats from privileged host software, using hardware-enforced isolation and memory protection together with attestation evidence describing a guest’s initial state and security configuration. Their intended boundaries do not include eliminating every side channel, protecting against malicious code already inside the guest, or guaranteeing availability against a host that stops scheduling it. Devices, shared I/O buffers, attestation verification, and key provisioning remain explicit trust considerations.
Performance and Resource Trade-offs
Virtualization overhead arises from several distinct paths: intercepted processor operations, virtual interrupt delivery, device emulation or backend processing, additional address translation, and host scheduling. Much ordinary guest code can execute directly on the processor, while selected events transfer control to the hypervisor. Consequently, overhead depends on event frequency and handling cost, not simply on the number of instructions executed. Hardware-assisted memory translation avoids maintaining shadow page tables but can require additional memory accesses during translation-cache misses. Virtual device processing may introduce exits, queue operations, copies, or transitions between execution contexts. There is therefore no single overhead percentage applicable to all virtual machines: a computation dominated by arithmetic can behave quite differently from a workload dominated by small network packets or synchronous disk writes.
CPU overcommitment assigns more virtual CPUs than the host can execute simultaneously. For example, assigning 32 virtual CPUs to a host with 16 physical cores creates a nominal 2:1 ratio if simultaneous multithreading is excluded; it does not mean that every guest receives half a core continuously. When guests are mostly idle, the arrangement can increase utilization without substantial contention. When they become runnable together, virtual CPUs wait for host scheduling. Some guest operating systems report part of this delay as steal time, although accounting varies by platform. A delayed virtual CPU holding a guest lock can also stall other virtual CPUs. Throughput measures completed work per unit time, latency measures completion time for individual requests, and predictability concerns their variation: acceptable aggregate throughput can coexist with occasional long pauses.
Bottlenecks depend on the workload and on shared resources beyond processor time. A CPU-bound numerical calculation may principally depend on core allocation, processor frequency, cache capacity, and memory locality. An I/O-intensive database instead may be limited by storage latency, queue contention, or the durability operations required for transaction commits. Network processing at a fixed bit rate becomes more demanding as packets become smaller because more packets require handling. Guests can also compete for last-level cache, memory bandwidth, storage-controller queues, and network links—the noisy-neighbor effect—even when they have separate virtual CPUs. Direct assignment of a GPU or network device can reduce software-path overhead, but does not eliminate device limits or contention elsewhere in the system; it can also constrain migration and resource sharing.
Meaningful comparisons require equivalent workloads and documented configurations. A virtualized and a nonvirtualized test should account for processor model, firmware settings, active cores, multithreading, memory capacity and placement, storage, network topology, operating-system versions, and application settings. Virtual CPU limits, reservations, host oversubscription, and device-backend configuration must also be stated. Comparing a cached dataset in one environment with uncached storage access in another measures more than virtualization. Managed runtimes may require warm-up for just-in-time compilation, while storage tests must distinguish cache effects from sustained device performance. Repeated measurements and configuration records support reproducibility.
Results should include throughput and a latency distribution rather than averages alone. A 99th-percentile latency of 100 milliseconds means approximately 99% of measured requests completed within that interval; the remaining requests may take substantially longer. Comparisons must specify offered load, concurrency, test duration, and whether request generation continues independently of server response time. A system tested near saturation may exhibit rapidly increasing queueing delay despite only a small throughput change. Dedicated-host measurements characterize a different operating condition from tests with competing guests, and both can be informative when their conditions are explicit.
Consolidation can reduce the number of powered-on servers by placing workloads with complementary demand patterns on shared hardware. Potential savings include host energy, cooling, rack space, and hardware expenditure, but management, licensing, storage, and resilience requirements also affect operational cost. Server power consumption does not decline proportionally with CPU utilization, so eliminating an underused host can save more energy than spreading the same work thinly across several hosts. Conversely, dense consolidation may increase contention and require spare capacity for failures or demand peaks. Energy comparisons therefore need both total consumption and completed useful work—for example, joules per transaction—under specified performance requirements.
Containers, Lightweight VMs, and Design Directions
System VMs and operating-system containers expose different execution boundaries. A system VM normally runs its own guest kernel against virtual processors, memory, and devices. A container instead isolates processes while retaining the host kernel: on Linux, namespaces separate views of resources such as process identifiers, mounts, and networking, while control groups account for and constrain resource consumption. Container images generally package application binaries, libraries, and filesystem content rather than a bootable guest kernel. Consequently, Linux containers require a compatible Linux kernel interface; running them on Windows or macOS commonly involves a Linux VM. A VM can support a different guest operating system when its virtual hardware is compatible. Neither boundary guarantees security, but containers place the shared kernel within every container’s isolation boundary, whereas VMs interpose a hypervisor between guest kernels and physical resources.
Containers and VMs are frequently combined rather than deployed as alternatives. Container orchestration workers can themselves be VMs, allowing infrastructure operators to allocate machines independently of application packaging and scheduling. Multiple containers then share each worker’s guest kernel, while different workers retain VM-level separation. Sandboxed container runtimes add another arrangement: Kata Containers runs container workloads inside lightweight VMs, integrating with container-management interfaces while supplying a separate guest kernel. Depending on the runtime and configuration, the isolation unit may encompass a pod containing several cooperating containers rather than one VM per process. This approach preserves much of the container deployment model but introduces guest boot, memory allocation, and host–guest communication costs.
A microVM is a system VM designed around a deliberately small virtual hardware configuration, not a separate class of processor virtualization. Amazon Web Services introduced Firecracker as an open-source virtual machine monitor in 2018 for services including AWS Lambda and AWS Fargate. It uses Linux’s Kernel-based Virtual Machine interface and a reduced device model with virtio networking and block storage, omitting much of the legacy hardware emulation found in general-purpose machine models. Its minimal configuration was reported to support startup in under 125 milliseconds and memory overhead below 5 MiB; these figures describe particular configurations, not universal application-readiness guarantees. Fewer emulated devices can reduce initialization work and the code exposed to guest input, although security still depends on the retained device implementations, host kernel, and management environment.
Unikernels reduce software inside the guest rather than merely simplifying its virtual hardware. A unikernel combines application code with selected operating-system services into a specialized image, commonly built using a library operating system. The MirageOS work presented at ASPLOS in 2013 demonstrated this approach using OCaml applications compiled with required networking and system components. Unlike an ordinary container image, a hypervisor-targeted unikernel does not depend on the host kernel to provide its application’s system-call environment. Unlike a conventional guest installation, it may omit a general-purpose shell, package manager, and multiprocess user environment. These choices change debugging and deployment: updating an application commonly means rebuilding and replacing the image rather than modifying a running general-purpose system.
Rapid startup involves more than launching virtual processors. Image distribution, storage attachment, network configuration, guest initialization, and application warm-up can dominate readiness time. Snapshot restoration can bypass repeated initialization, but cloned state requires care with random-number generation, credentials, clocks, and network identity. Migration presents a different challenge when guests use directly assigned devices: transferring processor and memory state is insufficient if device queues, firmware state, or accelerator memory cannot also be captured and restored. Migration support for a GPU or other device therefore depends on the device, driver, firmware, and virtualization stack rather than following automatically from VM support.
Heterogeneous processors further complicate portability because instruction extensions, accelerator interfaces, and memory-coherence arrangements may differ between source and destination machines. Masking processor features can improve migration compatibility while preventing applications from using newer instructions. Confidential-computing designs introduce another tension: encrypting guest memory against infrastructure software restricts ordinary host-side inspection, debugging, and state extraction. Migration and observability consequently require explicitly supported mechanisms, such as protected state-transfer protocols or guest-authorized telemetry. Their availability and guarantees remain specific to the hardware architecture and implementation.