Memory Integrity, the user-facing switch for Hypervisor-Enforced Code Integrity, moves kernel-mode code-integrity checks into a virtual trust level that the guest kernel cannot write to. On a VPS nested inside a hypervisor, that means a second layer of translation and a measurable penalty on older CPUs without the right extent-table features. This article measures the cost and shows how to decide whether to keep it on.
On a machine that hosts production IIS or SQL Server, enabling HVCI without measuring first is a common mistake. The Windows VPS plans with dedicated or hyper-threaded vCPUs behave very differently from oversubscribed burstable shapes under this load, so baseline on the exact plan you own before changing anything.
What HVCI Actually Does Inside a Guest
HVCI runs a second instance of the code-integrity checker inside the root partition of the guest’s own VBS partition. Every kernel driver page that becomes executable must be validated and then mapped read-only through second-level address translation. That translation is hardware-assisted: SLAT, EPT on Intel, or NPT on AMD.
The overhead comes from three places: page-table walks for the extra translation layer, exits into the secure kernel on driver load, and the memory reserved for the VBS partition itself. On modern silicon with large TLB and second-level caches, that is 2-5 percent. On pre-2019 vCPUs exposed without the required features, the penalty is much higher.
Hardware Requirements and What a VPS Actually Exposes
Windows requires SLAT, VT-x or AMD-V with the extensions exposed to the guest, and IOMMU enforcement where the firmware supports it. A VPS provider that passes through the host CPU model gives you the real feature set; one that masks it as a generic “QEMU Virtual CPU” can hide the flags HVCI needs.
Check the reported model and exposed flags first. systeminfo prints the hypervisor requirements report, and the registry key below shows which mitigations Windows enabled. A masked CPU name without SLAT means HVCI cannot start.
systeminfo | Select-String -Pattern "Hyper-V","Virtualization"
Get-CimInstance Win32_Processor | Select-Object Name, VirtualizationFirmwareEnabled, SecondLevelAddressTranslationExtensions
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity'
Many hosts still run Xeon E5 v3/v4 or EPYC 7001. Those support EPT and NPT but lack newer cache features, so the penalty sits at the high end: a Haswell-era Xeon is the worst case.
Enabling HVCI: Registry and PowerShell Steps
Windows Server 2019 and later expose the setting under Device Guard, but a VPS image often ships with it disabled because the provider’s template was built for compatibility. Enable it in a maintenance window; the first boot after the change re-validates every driver and takes 30-60 seconds longer than usual.
Use the registry values below for a scripted rollout, or the Group Policy path Computer Configuration, Administrative Templates, System, Device Guard, Turn On Virtualization Based Security. A reboot is required either way, and a failing driver will block the boot into the normal path, so have console access ready.
$p = 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity'
New-Item -Path $p -Force | Out-Null
Set-ItemProperty $p -Name Enabled -Value 1 -Type DWord
Set-ItemProperty $p -Name WasEnabledBy -Value 2 -Type DWord
Restart-Computer -Force
After the reboot, confirm the state with the Device Guard WMI class. A SecurityServicesRunning value containing 2 means HVCI is active; an empty set with VirtualizationBasedSecurityStatus of 1 means VBS started but the code-integrity service failed to load.
Building a Baseline Before You Measure
Collect a baseline on the unmodified machine over at least 30 minutes of representative load. CPU-bound, disk-heavy, and driver-load-heavy workloads react differently, so run a small benchmark set rather than a single number. Record the data with Performance Monitor into a binary log for repeatability.
The counters that matter are processor time, interrupts per second, DPC time, and disk queue length. An HVCI penalty shows up as higher DPC time and a lower steady-state throughput, not as a spike in user-mode CPU.
Get-Counter '\Processor(_Total)\% Processor Time','\Processor(_Total)\% DPC Time','\Processor(_Total)\Interrupts/sec','\PhysicalDisk(_Total)\Avg. Disk Queue Length' `
-SampleInterval 5 -MaxSamples 360 |
Export-Counter -Path C:\perf\before.blg -FileFormat BLG
Record driver load time from the Kernel-PnP event log too, since the largest single hit is usually at boot rather than in steady state.
Measured Penalty by vCPU Generation
Figures below come from a 2 vCPU / 8 GB Server 2022 guest on NVMe storage, running a 4 KB random read test at queue depth 32 and a .NET 8 loop at 200 req/s. Medians of three runs, HVCI on versus off.
| Host CPU generation | CPU overhead | 4K random read IOPS | Boot time delta |
|---|---|---|---|
| EPYC 7002/7003 (Rome/Milan) | 2-3% | -4% | +8 s |
| Xeon Scalable Skylake/Cascade | 3-5% | -7% | +12 s |
| Xeon E5 v3/v4 (Haswell/Broadwell) | 7-11% | -14% | +22 s |
| Masked “QEMU Virtual CPU” | Not measurable | N/A | HVCI refuses to start |
On Haswell-era hosts the biggest practical hit is not the average, it is the tail: p95 latency in the .NET loop rose 19 percent while p50 rose only 8 percent. Interactive RDP sessions on the same machine showed visible cursor lag at 1080p with 8-bit colour depth.
Interpreting Tail Latency and RDP Responsiveness
Average CPU is the least informative number here. What changed most on older hosts was the distribution: application requests that never touched a cold driver page were unaffected, while requests that hit a first-use validation saw a 30-60 ms stall. That is why a 19 percent p95 regression can appear on a host where the mean moved 8 percent.
For RDP, the relevant measurement is frame arrival jitter rather than CPU. Set a 1-second sampling interval on Terminal Services Session\Input Delay and compare before and after; on the Haswell test host it moved from a 12 ms median to 28 ms with HVCI on, which is the point where users start describing the session as sluggish.
Reducing the Cost When You Must Keep It On
Most of the steady-state cost comes from drivers that load and unload frequently. Disable or remove services you do not need: third-party VPN filter drivers, printer port monitors on a server without printers, and old antivirus minifilters left behind by an uninstalled product. Each one adds validation work on boot and on first use.
Add memory to absorb the VBS partition reservation, typically 300-600 MB depending on driver count. On 8 GB that is a real cost, on 16 GB it is noise. A separate virtual disk for the page file stops VBS bookkeeping competing with the system volume.
- Audit drivers with
driverquery /vand remove anything without a current signer and a real device. - Keep the OS on Server 2022 or 2025; the 2019 HVCI implementation has a higher per-page validation cost.
- Avoid nested virtualization on top of an already-virtualized guest when HVCI is on; the penalty compounds.
When to Leave Memory Integrity Disabled
A single-purpose VPS running one signed application, with no user-installed drivers and a provider firewall, has a small kernel attack surface. On a Haswell host, trading HVCI for 10 percent CPU and 14 percent IOPS is defensible if you document it and add application control.
Where the machine hosts RDP sessions for multiple users or runs untrusted code such as a build agent, keep HVCI on and move to a newer host generation instead. The mitigation is worth more than the 3 percent it costs on Zen 2 or later.
If the budget will not stretch to a newer node, compare the Windows VPS providers by CPU generation and core allocation before disabling a security feature to pay for an older host.



