On July 14, 2026, Microsoft merged a change into the master branch of Windows Subsystem for Linux (WSL) that separates user processes from core processes using cgroup v2. When memory is exhausted during operations like compiling, Linux-side applications and the processes running WSL itself can collapse together, sometimes leaving WSL unresponsive even after the load subsides. To curb this chain reaction, a new user cgroup sets memory and CPU limits, while keeping processes like mini_init outside of it. However, this is not yet a release to the public build. The implementation was merged after the latest pre-release, 2.9.4, and Microsoft has not indicated which version number or timeframe will bring it to users.
32MiB and 0.01 Cores to Prevent Total Collapse

What this change aims to protect is not the memory-hungry application itself, but the core processes that keep WSL running. It creates a cgroup called /wsl-user inside the WSL 2 lightweight virtual machine, and moves user-launched processes underneath it. systemd, the session leader, and boot commands run at startup are also subject to the same limits. Plugin processes not belonging to any distribution are placed in a non-distro group.
Meanwhile, processes such as mini_init, GNS, Plan9, and WSL init remain in the root cgroup, which has no limits set. mini_init is the process responsible for launching each WSL 2 distribution, mounting VHDs, and creating namespaces. If this process gets caught up in user load, WSL can fail to recover from an error state even after the memory-consuming application has terminated. Moving core processes to a separate resource pool is the central idea behind this design change.
The memory.max for /wsl-user is set to the total memory inside the virtual machine (as returned by Linux's sysinfo) minus 32MiB. When the limit is reached and usage cannot be reduced, the OOM killer within the cgroup terminates user processes. Because core processes sit outside this target group, they retain enough capacity to continue error handling and communication. This is not a mechanism that fixes which application gets terminated, but it does make WSL-wide unresponsiveness less likely to occur.
CPU is divided under the same principle. For a 100,000-microsecond period, the implementation subtracts 1,000 microseconds from the total time across all logical CPUs assigned to the virtual machine, and writes the result to cpu.max. What remains for core processes is a small allotment—equivalent to about 0.01 logical cores. Still, this provides an escape route for scheduling mini_init and similar processes even when user processes have filled up all available CPU.
The GitHub Issue that triggered this work reported a case where WSL 2.6.3.0 crashed unexpectedly while building the Vulkan SDK with ninja. The reporter said they experienced this on two Windows 11 PCs. However, the WSL team recorded this phenomenon as non-deterministic and hard to reproduce, and no automated test was added to reproduce the original OOM case under fixed conditions. This design narrows the failure path, but it is not a guarantee that crashes under heavy load will never happen again.
Windows-Side Limits and WSL-Internal Limits Serve Different Roles
WSL 2 has long had a feature that lets users limit memory and logical processor count via .wslconfig, placed in the Windows user folder. According to official documentation, the default for memory is 50% of the total memory installed on Windows, and processors defaults to the same number of logical processors as Windows. This setting determines the total amount of resources passed from the Windows side to the entire WSL 2 virtual machine.
The new cgroup further divides that allocated pool into two. The distinction works as follows:
| Boundary | Where It's Set | Target | Purpose |
|---|---|---|---|
| WSL 2 VM allocation | Windows-side .wslconfig |
Entire virtual machine | Determines memory and CPU WSL can use from Windows |
/wsl-user limit |
WSL-internal cgroup v2 | Total of user processes | Reserves ~32MiB and ~0.01 cores for WSL core processes |
distro-<init pid> |
Under /wsl-user |
Processes per distribution | Separates each distribution's systemd cgroup hierarchy |
In other words, this doesn't newly reserve 32MiB from the entire Windows host. If you've already limited WSL 2's memory to a specific value via .wslconfig, the new memory.max is calculated based on the total amount visible inside that virtual machine. This isn't a change that expands the boundary between Windows and WSL—it's a change that prevents user load from fully consuming the pool it's been given, right down to the last byte.
This distinction also matters operationally. Previously, lowering the memory limit in .wslconfig could reduce impact on the Windows side, but once that limit was reached inside WSL, core processes were subjected to the same pressure. With the new implementation in place, it becomes possible to maintain separate limits: an outer limit that protects Windows, and an inner limit that keeps WSL itself alive.
Separating systemd Across Multiple Distributions
Another change assigns each distribution a cgroup named /wsl-user/distro-<init pid>. In environments with systemd enabled, it further creates systemd and non-systemd child groups. According to WSL's official technical documentation, each distribution runs with separate mount, pid, and UTS namespaces. However, the cgroup hierarchy wasn't sufficiently separated, leading to cases where multiple systemd instances tried to use the same path and collided.
Indeed, users of WSL 2.7.3.0 reported that when launching multiple Ubuntu environments, systemd user sessions failed to start in some cases. The logs showed Device or resource busy, and user@1000.service could not be attached to the cgroup. There were also reports with WSL 2.7.8.0 that running Debian and Ubuntu simultaneously caused Debian's poweroff to hang indefinitely.
By separating the cgroup root for each distribution, one systemd's hierarchy no longer competes with another's. In addition to manual verification of launching Ubuntu and Debian simultaneously, the PR added unit tests for cgroup placement, including cases with and without systemd and with the isolation feature disabled. It also verifies that cgroups for terminated distributions are removed and that stale hierarchies don't linger.
That said, this is not an implementation that reserves 32MiB per distribution. The memory and CPU limits sit at the higher-level /wsl-user, shared across all user load. What distro-<init pid> resolves is primarily hierarchy collisions, not per-distribution resource guarantees.
Not Yet in 2.9.4, and an Escape Route for cgroup v1 Users
PR #40519 was merged into master at 13:10 JST on July 14. WSL 2.9.4, a pre-release published earlier that same day at 6:06 JST, does not include this PR in its changelog. Microsoft has not indicated when it will land in the next pre-release or stable version, so at present, running wsl --update does not guarantee general users access to this new protection.
There are also compatibility conditions. Because the new hierarchy relies on cgroup v2, it is incompatible with older workloads that require cgroup v1. The implementation allows isolation to be disabled by setting isolateDistroCgroup=false under [wsl2] in .wslconfig. The default is true. Disabling it preserves cgroup v1 compatibility, but also forfeits both the resource pool that protects core processes during OOM events and the per-distribution hierarchy separation.
Additionally, if enabling a cgroup controller or moving a process fails, the implementation logs a warning or error and continues processing. A state where the protection feature only partially functions is anticipated. Once a distributed version is released, it will be necessary to check whether /sys/fs/cgroup/wsl-user is created, and whether existing container or systemd operations are affected. Beyond the version number, the key question is whether WSL's control path can remain responsive even after heavy load—that will be the measure of this change's success.