In this lesson, you will learn how to prevent memory leaks and "ghost" actors by implementing robust cleanup logic during the transition between network levels or unexpected client disconnections.
The Challenge of Persistent State
When a server travels to a new map (level transition) or a player drops their connection, the UWorld is torn down. While Unreal Engine automatically cleans up actors by default, custom systems—such as non-replicated references in a Singleton, pending RPC queues, or global manager arrays—often fail to release their pointers. This leads to dangling pointers or "ghost actors" that persist in memory, bloating your process and causing crashes when accessed after a transition.
Implementing Cleanup Guards
To manage lifetime effectively, you must utilize the lifecycle hooks EndPlay and OnEndPlay provided by AActor. Because these methods fire both on server shutdown and when a client disconnects, they are the ideal location to nullify references and clear pending tasks.
Consider a custom GameSessionManager that tracks active players. If you don’t clear these references, the manager will hold a reference to an actor that no longer exists in the new UWorld.
void AMyPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
// Ensure we are not leaving dangling references in managers
if (AMyGameMode* GM = Cast<AMyGameMode>(GetWorld()->GetAuthGameMode()))
{
GM->UnregisterPlayerSession(this);
}
// Always call the Super to allow UE to perform its own cleanup
Super::EndPlay(EndPlayReason);
}
Preventing Ghost Actors
"Ghost actors" usually occur when a client thinks an actor exists because a reference was stored before a transition. To solve this, always validate your actors using IsValid()—which checks for null pointers and PendingKill status—before executing any logic on them.
Furthermore, if your game uses persistent GameState or PlayerState, ensure you rely on GetWorld()->IsServer() checks before attempting to broadcast any final "destruction" logic to avoid trigger-happy clients attempting to clean up server-side data they no longer have authority over.
Key Takeaway: Use EndPlay to explicitly decouple your actors from global managers and always validate references with IsValid() to ensure your system remains resilient to sudden network state changes.