World Partition builders crash with "Out of Page File" — HasExceededMaxMemory() only checks physical RAM, never commit charge (affects all WP builders)

Summary

The memory governor that throttles World Partition builders, FWorldPartitionHelpers::HasExceededMaxMemory() (WorldPartitionHelpers.cpp:249), decides only from physical-RAM residency (available physical, process working set). On any machine with a page file, Windows keeps those signals healthy by trimming working sets and paging committed memory out to disk — so the governor never throttles. The builder keeps dispatching tasks, and commit charge climbs unbounded until it hits the system commit limit (physical + page file) and the process dies with “Out of Page File.” The metric that actually runs out — commit charge — is never consulted, even though the platform layer already computes it (MemStats.AvailableVirtual, MemStats.UsedVirtual). This lives in core FWorldPartitionHelpers, so it affects every WP builder (HLOD, navmesh, MeshPartition, …), and is worst on ≤32GB machines (typical CI/build hardware).

What Type of Bug are you experiencing?

Foundation (C++ Tools, Profiling, & Pipeline)

Steps to Reproduce

  1. Open a large World Partition map whose build processes enough actors to exceed physical RAM (our case: a MeshTerrainMode “Mega Mesh” / MeshPartition map of thousands of sections; any large WP build that fills memory
    will do).
  2. Ensure a sizable Windows page file (the default system-managed size is enough).
  3. Trigger a whole-world build — e.g. Build → Build Mesh Partition (force rebuild), or any WorldPartition builder commandlet over the full map.
  4. Watch the editor/commandlet process in Task Manager → Details → Commit size (and Performance → Memory → Committed).

Expected Result

As commit headroom (available page file) runs low, the builder’s memory governor throttles task dispatch / forces garbage collection, so the build completes — slowly if necessary — without exhausting the system commit limit.

Observed Result

Commit charge climbs monotonically while the process’s resident physical stays modest (Windows trims the working set and pages out). The governor never fires because it only watches physical residency. Commit reaches the system commit limit → allocation fails → “Out of Page File” hard crash. On our box the crash also dropped displays and required a remote reboot. Enlarging the page file only delays the crash and induces heavy disk thrash; shrinking it makes the crash arrive sooner. The page-file size is a red herring — the governor is watching the wrong metric.

Affects Versions

5.8

Platform(s)

Windows

Additional Notes

Engine / platform: UE 5.8, Windows 11 (reproducible on any Windows host with a page file; the logic is platform-independent).

Root cause — WorldPartitionHelpers.cpp:249:

  bool FWorldPartitionHelpers::HasExceededMaxMemory()
  {
      const FPlatformMemoryStats MemStats = FPlatformMemory::GetStats();
      const uint64 MemoryMinFreePhysical = 1llu * 1024 * 1024 * 1024;                           // 1 GB
      const uint64 MemoryMaxUsedPhysical = FMath::Max(32llu*1024*1024*1024, MemStats.TotalPhysical / 2);
      const bool bHasExceededMinFreePhysical = MemStats.AvailablePhysical < MemoryMinFreePhysical;
      const bool bHasExceededMaxUsedPhysical = MemStats.UsedPhysical >= MemoryMaxUsedPhysical;
      return bHasExceededMinFreePhysical || bHasExceededMaxUsedPhysical;                          // physical only
  }
  • AvailablePhysical < 1GB effectively never trips: AvailablePhysical (ullAvailPhys) includes the standby list, which Windows keeps padded by paging. It only collapses once the page file is already full — i.e. when you are already crashing.
  • UsedPhysical >= max(32GB, RAM/2) does not trip either: under pressure Windows trims the process working set (evicts resident pages to the page file), so resident physical stays low while committed memory balloons.

The max(32GB, …) floor makes the used-physical check dead on small machines. On a 32GB box the threshold is 32GB — you can never have a 32GB working set on a 32GB machine, so that clause can never fire; on 16GB it is even more impossible. The check only has a theoretical chance on >64GB machines (and trimming still defeats it there). So the existing safety net is weakest on exactly the ≤32GB hardware typical of CI/build farms (often decommissioned dev desktops with less RAM than a working dev box). If a whole-world build crashes on a dev machine, it is guaranteed to crash — unattended — on CI.

The numbers needed are already computed — WindowsPlatformMemory.cpp:

  // :340  AvailableVirtual is clamped to available page file == available COMMIT headroom
  MemoryStats.AvailableVirtual = FMath::Min(MemoryStats.AvailableVirtual, MemoryStatusEx.ullAvailPageFile);
  // :344-345  PagefileUsage == commit charge
  MemoryStats.UsedVirtual = ProcessMemoryCounters.PagefileUsage;

HasExceededMaxMemory() reads neither, even though the GC diagnostics at WorldPartitionHelpers.cpp:276 already log AvailableVirtual.

Suggested fix — throttle on commit pressure, two clauses (each covers a mode the other misses):

  // (a) thrash detector — THIS process is paging itself out (commit >> resident). Self-scaling.
  const bool bThrashing = (MemStats.UsedPhysical > 0) &&
      ((double)MemStats.UsedVirtual / (double)MemStats.UsedPhysical) > 2.0;   // tune vs measured baseline
  // (b) absolute backstop — the SYSTEM is about to run out of commit, whoever is using it.
  const uint64 MemoryMinFreeVirtual = 8llu * 1024 * 1024 * 1024;              // ~8 GB commit headroom
  const bool bHasExceededMinFreeVirtual = MemStats.AvailableVirtual < MemoryMinFreeVirtual;

  return bHasExceededMinFreePhysical || bHasExceededMaxUsedPhysical
      || bThrashing || bHasExceededMinFreeVirtual;

Note on (a): a healthy UE editor already runs commit:resident ~1.3–1.6:1 (untouched allocator arenas, file-backed code/asset pages, idle working-set trim), so a 1.25 trigger would false-fire; ~2.0 is a safe default — measure the resting ratio and set ~1.5× it. Clause (b) catches the system-wide case the process-local ratio cannot see. Because the fix is in FWorldPartitionHelpers, it benefits all WP builders.

Call site (for context): WorldPartitionMeshPartitionBuilder.cpp:726 gates dispatch on HasExceededMaxMemory() with a hardcoded MaxTasksInFlight = 16 (…Builder.h:208, not a cvar), so there is no user-facing way to reduce concurrency to bound peak commit either.

Related (possibly a separate report): the MeshPartition build commands are whole-world only — there is no “compile loaded/selected sections” path, so iterative work has no choice but the whole-world bake that triggers this crash. The live loaded-region preview (AInteractiveSection) is transient/editor-only and is not persisted output.

hi @Durrik1

The message “Out of Page File” is you need a bigger Virtual Memory Page File see

How to create a 64GB 64000 Virtual Memory Page file

UE 5.8 and UEFN need this to run properly now days

Thanks! “Out of Page File” is the symptom, but I don’t think a bigger page file is the fix and my setup actually shows why.

The page file was already set to system-managed (no fixed limit) when it crashed. It still died, at ~220 GB system commit because “system managed” is really capped by free disk space, and the build kept committing past what the disk could back. I had 320 gb free on my disk at the time with a page file of already 160 gb before I started the build. I’ve since freed up space and pinned it to 512 GB (≈576 GB commit limit with my 64 GB RAM). Watching commit during a build, it climbs to ~300 GB even when picking up a build that’s already ~80% cached, so I don’t expect a full forced rebuild to stay under 512 GB either.

The real issue is that commit grows unbounded, there’s no page-file size (or disk) that’s “enough,” because the build never stops committing. The WorldPartition build governor
(FWorldPartitionHelpers::HasExceededMaxMemory()) only throttles on physical RAM, which Windows keeps healthy by paging, so it never sees the commit pressure and never throttles. Bigger/unbounded page file just moves the cliff; it doesn’t stop the walk toward it.