Introduction
Unreal Engine uses an automatic garbage collection system to manage memory and clean up unused objects. However, when GC is triggered too frequently or at inopportune moments, it can cause performance hitches, frame drops, and stuttering. This issue becomes particularly problematic in large, open-world games or projects with high object churn. This article explores common causes of garbage collection performance issues in Unreal Engine, debugging techniques, and best practices for optimizing memory management.
Common Causes of Garbage Collection Performance Issues
1. Excessive Garbage Collection Calls During Gameplay
Unreal Engine automatically triggers garbage collection based on allocated memory, but frequent GC execution can cause performance drops.
Problematic Scenario
// Default GC threshold
[/Script/Engine.GarbageCollectionSettings]
timeBetweenPurgingPendingKillObjects=5.0
By default, Unreal Engine purges unused objects every 5 seconds, which can lead to noticeable stuttering.
Solution: Increase GC Threshold to Reduce Frequency
// Increase threshold to reduce GC interruptions
[/Script/Engine.GarbageCollectionSettings]
timeBetweenPurgingPendingKillObjects=30.0
Increasing `timeBetweenPurgingPendingKillObjects` reduces the frequency of garbage collection cycles, preventing frequent performance drops.
2. Large Numbers of Unreferenced Objects Causing Memory Spikes
Unreal Engine’s GC only collects unreferenced objects. If objects are not properly dereferenced, they accumulate in memory.
Problematic Scenario
UPROPERTY()
UTexture2D* UnusedTexture;
If `UnusedTexture` is never set to `nullptr`, it remains in memory indefinitely.
Solution: Explicitly Dereference Objects Before They Become Unused
UnusedTexture = nullptr;
MarkPendingKill();
Setting objects to `nullptr` ensures they are properly flagged for garbage collection.
3. Excessive Use of `Tick` Functions Leading to Unnecessary Object Retention
Using `Tick()` for continuous updates on multiple objects can cause performance issues if not managed correctly.
Problematic Scenario
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
ProcessObject();
}
If `ProcessObject()` creates new objects each frame without proper cleanup, the engine will accumulate unused objects in memory.
Solution: Disable Tick When Not Needed
void AMyActor::BeginPlay()
{
Super::BeginPlay();
SetActorTickEnabled(false);
}
Disabling `Tick()` when not required prevents unnecessary object creation and retention.
4. Improperly Managed Dynamic Object Spawning
Creating objects dynamically without proper destruction leads to excessive memory usage.
Problematic Scenario
UWorld* World = GetWorld();
AActor* NewActor = World->SpawnActor(MyActorClass, SpawnLocation, SpawnRotation);
If `NewActor` is not properly destroyed, memory usage will increase over time.
Solution: Use Smart Pointers and Proper Cleanup
if (NewActor)
{
NewActor->Destroy();
}
Destroying unused actors prevents memory leaks and excessive GC load.
5. Inefficient Use of UPROPERTY Markup Leading to Uncollected Objects
Using incorrect `UPROPERTY` specifiers can prevent objects from being garbage collected.
Problematic Scenario
UPROPERTY()
UObject* MyObject;
If `MyObject` is marked with `UPROPERTY()` but is not intended to persist, it may not be collected.
Solution: Use `Transient` or `WeakPtr` Where Appropriate
UPROPERTY(Transient)
UObject* MyObject;
Marking objects as `Transient` ensures they are not retained longer than necessary.
Best Practices for Optimizing Garbage Collection in Unreal Engine
1. Adjust GC Settings to Reduce Stuttering
Increase `timeBetweenPurgingPendingKillObjects` to avoid frequent GC cycles.
Example:
[/Script/Engine.GarbageCollectionSettings]
timeBetweenPurgingPendingKillObjects=30.0
2. Explicitly Dereference Objects When No Longer Needed
Set unused objects to `nullptr` to ensure proper GC handling.
Example:
MyObject = nullptr;
3. Disable `Tick()` When Not Required
Prevent unnecessary updates by disabling `Tick()` in idle actors.
Example:
SetActorTickEnabled(false);
4. Use Smart Pointers for Dynamic Object Management
Use `TWeakObjectPtr` instead of raw pointers for temporary objects.
Example:
TWeakObjectPtr TempObject;
5. Monitor GC Performance Using Unreal Insights
Use Unreal Insights to track memory usage and GC impact.
Example:
Window → Developer Tools → Unreal Insights
Conclusion
Performance degradation and unexpected stuttering in Unreal Engine often result from improper garbage collection management, excessive object retention, and inefficient memory usage. By adjusting GC settings, explicitly dereferencing objects, disabling unnecessary `Tick()` functions, and using Unreal Insights for performance monitoring, developers can optimize memory management and maintain a smooth gameplay experience.