We experience frame freezing when moving around in a World Partition level. The World Partition system loads and unloads sublevels dynamically, but occasionally, we encounter frame freezes when the garbage collector starts.
Here are our garbage collector parameters from the GameUserSettings file:
[/Script/Engine.GarbageCollectionSettings]
gc.TimeBetweenPurgingPendingKillObjects=120.0
gc.MaxObjectsNotConsideredByGC=0
gc.SizeOfPermanentObjectPool=1000000
gc.FlushStreamingOnGC=False
gc.NumRetriesBeforeForcingGC=10
gc.AllowParallelGC=True
gc.MultithreadedDestruction=True
gc.CreateGCClusters=True
gc.ActorClusteringEnabled=True
gc.BlueprintClusteringEnabled=True
gc.VerifyUObjectsAreDestroyed=False
gc.IncrementalBeginDestroyEnabled=True
gc.IncrementalBeginDestroyTimeLimit=2.0
There is some optimization we can apply for avoid this freeze ?
Observations from frame spikes in the provided Unreal Insights Trace seem to show that:
The Game Thread is spending a lot of time waiting for the Render Thread.
The Render Thread spends most of its budget on cloth, HISMs and waiting for File IO threads
This could be due to Sublevels loading in during runtime ( if I am correctly understanding the provided description of the problem ).
If you are successfully using World Partition I would recommend merging the sublevels into one map ( and potentially using data layers and one file per actor for art management etc ) and spatially loading the level. By mixing Sublevels in with World Partition the Sublevels may not be getting the advantage of the World Partition memory paging system and may be initializing the entire level ( or just more than necessary ) when it is loaded in during runtime.
With Regard to Garbage collection, there are some long CollectUnreachableTask sections. Things that may impact the time this takes to run in your project could include:
A large World Partition cell size resulting in many objects that need to be traversed.
Hard object references and long dependency chains in Actors ( e.g an actor with many components who in turn reference other actors or systems who then int turn reference other actors etc)
Potential Memory Leaks
You can view memory management by adding the `memory` trace option to the capture command, You can also ‘listen’ to what the garbage collector is doing by extending from the FUObjectArray::FUObjectDeleteListener, and FUObjectArray::FUObjectCreateListener classes.
Potential next steps:
Do another trace capture to attempt to discern the bottlenecks in both the rendering thread and the garbage collection. Start the trace with at least the following flags `trace=default, assetloadtime,file,memory,cpu,gpu` and utilise the `Trace.Bookmark` and `Trace.Screenshot` commands during interesting level areas of the capture.
Do a pass on your Blueprints/ C++ to ensure that they ( and their components ) do not tick if they don’t need to and that all hard references are indeed required ( e.g AsyncLoading any Data Assets and Asset Tables in begin play as opposed to setting them in defaults etc ).
Refactor the level to more effectively utilize the World Partition system ( although this is probably best done once the profiling confirms the expected result )
If you can send through an updated trace file or any further information or files I am happy to continue the investigation.
Our goal is to use pak files and a sublevel system to load a georeferenced terrain, so we don’t have a main level containing all the data. Currently, there are 256 sublevels per geocell.
Tell me if the new trace can help for finding the bottleneck.
this looks like a specific case of bad GC performance that we’ve recently encountered with other licensees, too.
Just to confirm, do you have IOStore containers enabled or did you disable this to build your app with pak files only?
Could you test your application with IOStore containers instead of pak files (if necessary just package as one project and skip the external pak loading)?
The old loading path without IOStore can have a significant impact on the CollectUnreachableObjectsTask times, so this would be something to verify first before proceeding with generic optimizations to object counts and dependencies.
Just to confirm, can you also run your application with the -LogCmds=“LogGarbage verbose” startup parameter and copy&paste the “LogGarbage:” lines here?
For generic stats please also post the output of the “obj list -countsort” console command from a point within your application where a decent amount of levels are loaded.