Summary
When IsPartitioned is enabled on a Landscape with PCG Runtime Generation,
PCGPointData memory allocated by PCG Nodes in the PCG Graph continuously
accumulates as the player character moves across the map, and is never
properly released.
Note: PartitionActors are managed via an object pooling mechanism — they are
recycled back into a pool for reuse rather than being unloaded/destroyed when
the player moves out of range. However, even though the PartitionActor itself
persists (pooled) and gets reused for regenerating content at new locations,
the PCGPointData associated with its PREVIOUS generation is never released.
This means old point data silently leaks every time a pooled PartitionActor
is reused for a new location.
We instrumented the engine source code by adding logging in the constructors
of UPCGPointData / UPCGPointArrayData (and in FPCGContext::NewPointData_AnyThread)
as well as in their destructors. The result confirms that these objects are
being created continuously as the player moves and PartitionActors are
recycled/regenerated, but their destructors are NEVER called throughout the
entire runtime session — regardless of how many times the underlying
PartitionActor has been recycled and reused for different locations. This is
direct evidence that the memory leak originates from PCG’s own partition
cleanup logic failing to release stale PCGPointData objects when a pooled
PartitionActor is reused, rather than being a general World Partition
streaming issue.
This issue reproduces on UE 5.6, and appears to share the
same root cause as FORT-919184 (submitted June 2025, confirmed on 5.5/5.6).
This memory leak has been observed to be triggered by at least two independent
paths:
- PartitionActor being recycled via the object pool as the player moves
(large-scale open world movement scenario). - A local PCGComponent being explicitly told to regenerate by an external
dependency system — for example, a voxel/dynamic terrain system that
modifies the landscape surface (digging, building, terrain deformation)
and then calls regeneration on the local PCGComponent to refresh the
vegetation/foliage that depends on the modified terrain.
In both cases, the PCGPointData associated with the PREVIOUS generation is
never released once new PCGPointData is created for the new content.
What Type of Bug are you experiencing?
Other
Steps to Reproduce
-
Create a large-scale Landscape with World Partition enabled
(the default Open World template can be used). -
Create a PCG Graph that samples the Landscape surface (e.g. simple tree
scattering). Note: the more PCG Nodes are used in the graph, the more
severe the memory leak becomes. -
On the PCG component, set “Generation Trigger” to “Generated at Runtime”
and enable “Is Partitioned”. -
On the PCG Graph, enable “Use Hierarchical Generation”. Set
“HiGen Default Grid Size” to 25600. Disable “2D Grid”. -
Set “Generation Radius 25600” to 0.
Note: this is to force PCG generation to be triggered frequently within
a limited test area during testing. -
Place a default Third Person character and add a PCGGenSource component to it.
-
On the PCGWorldActor, set the Landscape Cache’s “Serialization Mode” to
“Always Serialize” (otherwise PCG will fail to generate vegetation meshes
at runtime with an error). -
Run in PIE, Standalone mode, or a packaged build.
-
Capture a memreport (
memreport -full) once before the test starts. -
Move the character quickly around the scene, continuously triggering
PartitionActor refresh/creation. -
After moving for a while, capture another memreport. Compare the
PCG-related memory data between the two captures. -
(Recommended, decisive evidence) If engine source modification is
possible: add creation logging in FPCGContext::NewPointData_AnyThread /
UPCGPointArrayData / UPCGPointData constructors, and destruction logging
in the destructors of UPCGPointArrayData / UPCGPointData. This reveals
that UPCGPointArrayData / UPCGPointData memory is NEVER destroyed during
runtime, even though the underlying PartitionActor is being actively
recycled and reused (not unloaded/destroyed).
Expected Result
When a PartitionActor is recycled, or when a local PCGComponent is triggered
to regenerate, the PCGPointData associated with the PREVIOUS generation should
be released after the new PCGPointData for the new content has been created.
Regardless of how many times the PartitionActor is recycled or the PCGComponent
is repeatedly regenerated during continuous movement, memory usage should remain
roughly stable.
Observed Result
PCGPointData allocated by PCG Nodes is never released. Every time a partition’s
content is generated or regenerated — whether triggered by player movement,
or by a local PCGComponent being told to regenerate — a new PCGPointData is
created, but the PCGPointData from the PREVIOUS generation is never destroyed.
The count and memory footprint of PCGPointData grow continuously and unboundedly
as generation/regeneration events accumulate.
Captured data (UE 5.6, WindowsEditor, PIE):
- At 35.94s (near spawn point): PCGPointData Count = 9, ResExcKB = 677.87 KB
- At 268.03s (after moving ~53,000u): PCGPointData Count = 311, ResExcKB = 24,704.76 KB
(+3355% count increase, +3544% memory increase)
Decisive evidence via source instrumentation:
By adding logging to the constructors and destructors of UPCGPointData /
UPCGPointArrayData, we confirmed that these objects are being newly created on
every generation event, but their destructors are NEVER invoked throughout the
entire runtime session. This confirms the root cause lies within PCG’s own
point-data cleanup logic, which fails to release the previous PCGPointData
whenever a partition’s content is (re)generated.
Additional Note on UE 5.8 Testing:
We performed a similar test on UE 5.8 following the same reproduction steps.
However, the resulting memreport did not surface any PCGPointData /
PCGPointArrayData entries for comparison (the object class was absent from
the report entirely, not merely filtered out by size ranking).
We are NOT able to conclude from this alone that the issue has been fixed
in UE 5.8. This could be due to several reasons — for example, the underlying
PCG data class/storage may have been renamed or restructured in 5.8, or our
5.8 test may not have triggered a sufficient number of partition
generation/regeneration events to reproduce the leak. Without further
verification via source-level instrumentation (as described in Step 12 of
the reproduction steps) on UE 5.8 specifically, we cannot confirm whether
this issue has been resolved in that version.
Affects Versions
5.6
Platform(s)
Windows