Memory Management

From UE4: Community Wiki
Jump to: navigation, search

There are a few different memory management systems in UE4: garbage collection, smart pointers, and standard C++ memory management.

Garbage Collection[edit]

Garbage collection (GC) tracks UObject sub-classes, which include AActor and UActorComponent. When creating a new UObject, UE4 will automatically add them to its internal objects list, so even with improper use, it's not easy to have memory leaks, but it is easy to cause crashes. UObjects should never be created with new, but only with their default creation methods (NewObject, SpawnActor, CreateDefaultSubobject, ...).

Objects are primarily kept alive in 3 ways:

  • By having a strong reference (UPROPERTY) to them (from objects or structs that are also referenced)
  • By adding them to the list of void UObject::AddReferencedObjects(UObject* This, FReferenceCollector& Collector) (from objects or structs that are also referenced)
  • By adding them to the root set with UObject::AddToRoot (typically unnecessary)

When objects do not fulfill any of the above conditions, on the next GC cycle they will be marked as unreachable and garbage collected (destroyed).
Having an object as an Outer of another object does not automatically mean it will be kept alive. The same goes for default subobjects.

To force the destruction of objects that are still reachable, you can call MarkPendingKill on them, and it will force their destruction on the next GC cycle (you generally want to avoid doing this as that is what the garbage collection is for, and some classes, like AActor and UActorComponent do not support it).
The destruction of an object doesn't necessarily all happen in the same frame, when garbage collection starts on it, it will first call BeginDestroy (do not call this yourself), then, when ready FinishDestroy.
The GC runs in the game thread so it won't ever run as you are accessing an object from the game thread.

While the most common way of keeping alive objects is through a UPROPERTY, actors and components work differently:
levels reference their actors and actors reference their components. Both work by overriding the void UObject::AddReferencedObjects(UObject* This, FReferenceCollector& Collector) implementation and collecting what they do not want to be garbage collected. This means that even if there are no strong references to actors and components with an owner, they won't be garbage collected until manually destroyed, or their level is unloaded.

The garbage collector will clear references to garbage collected objects in any of these cases[1]:

  • A raw pointer declared with UPROPERTY (it will be set as nullptr)
  • In a UObject compatible container, such as TArray, TSet, or TMap, if declared with UPROPERTY (the affected elements will be set as nullptr but not removed)
  • In a TWeakObjectPtr (the reference isn't exactly cleared in this case but calling Get will now return nullptr)

Anytime code references an AActor or a UActorComponent, it has to deal with the possibility that AActor::Destroy is called on the actor or UActorComponent::DestroyComponent is called on the component. These functions will mark them for pending kill, thus triggering their garbage collection at the first chance it gets (note that destroying an actor also destroys all its component). Since the garbage collector automatically nulls out UPROPERTY pointers when it actually gets to destroy them, null-checking an actor or component pointer is sufficient to know it's safe to use, though you might also want to check IsPendingKill on them to avoid accessing them after they have been marked for destruction (TWeakObjectPtr already checks for this when retrieving the raw pointer).

bool IsValid(const UObject* Test) is a global function that automatically checks if an object pointer is non-null and not pending kill. UObjectBase::IsValidLowLevel and UObjectBase::IsValidLowLevelFast should not be used for GC checks, as on UPROPERTY pointers it will always return true, while on raw pointer it will return true or false depending whether the object had already been destroyed, but in the latter case it's also likely to crash the application as the pointed memory could have been overwritten.

If you write your own non-garbage classes that references garbage collected objects, you may want to sub-class FGCObject.

Garbage Collection Performance[edit]

The GC will run every x seconds, though it's possible to force its execution at any time. Given that for technical reasons the GC needs to go through every UObject in the same pass (it can't split reference counting over multiple frames), the bigger is the number of UObjects and the more UPROPERTY pointers these objects have, the slower the GC pass will be. The time taken by a pass will also be determined by the amount of objects it needs to destroy.

Unreal Smart Pointer Library[edit]

The Unreal Smart Pointer Library is for code that is not based on the UObject system. It is similar in function to the C++11 standard library smart pointers. Unreal Smart Pointers cannot be used to reference UObjects, because the garbage collector isn't aware of smart pointers[2].

Further reading[edit]


Related Legacy articles