Using Unreal Engine Level Streaming to Keep Memory Low in Large Worlds
Learn how to load and unload parts of a level at runtime with Unreal Engine's level streaming feature, see a C++ example, and understand the limits and common mistakes to avoid.
08 Oct 2025, 07:09 UTC

Why use level streaming
In Unreal Engine, level streaming lets you load and unload portions of a world while the game is running. This keeps memory usage low and enables large open‑world levels without forcing the player to wait for a full level load.
How level streaming works
The engine maintains a ULevelStreaming object for each streamed level. When you set SetShouldBeLoaded(true) and SetShouldBeVisible(true), the level is read from disk in a background thread. Once the data is fully loaded, its actors become visible and can be accessed by gameplay code.
Loading a level in C++
Place the level you want to stream in the Levels panel, right‑click it, and choose Convert to Streaming Level. Give it a clear name, for example Forest_Patch. Then use the following code to request loading and visibility:
// Called from any gameplay class that has a valid World reference
void AMyCharacter::RequestForestPatch()
{
UWorld* World = GetWorld();
if (!World) return;
// Find the streaming level object by name
ULevelStreaming* Stream = UGameplayStatics::GetStreamingLevel(World, TEXT('Forest_Patch'));
if (!Stream)
{
UE_LOG(LogTemp, Warning, TEXT('Streaming level Forest_Patch not found'));
return;
}
// Request load and make visible
Stream->SetShouldBeLoaded(true);
Stream->SetShouldBeVisible(true);
}
The level is loaded asynchronously. To know when it is ready, bind to the OnLevelLoaded delegate or poll IsLevelLoaded() before accessing actors:
if (Stream && Stream->IsLevelLoaded())
{
// Safe to spawn or reference actors from Forest_Patch
ATree* Tree = World->SpawnActor<ATree>(ATree::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator);
}
else
{
// Level still loading – handle accordingly (e.g., show a loading screen)
}
Unloading a level
To free memory when the player leaves the area, reverse the flags:
Stream->SetShouldBeLoaded(false);
Stream->SetShouldBeVisible(false);
The engine will begin unloading the level after the current frame, destroying its actors and releasing resources.
Limits and common pitfalls
- Loading delay: There is always at least one frame of hitch while data is read from storage. Do not expect instant teleportation into a streamed level.
- Actor access timing: Attempting to spawn, find, or reference actors before
IsLevelLoaded()returns true yields null pointers and can cause crashes. - Navigation data: AI navigation meshes are not automatically rebuilt when streaming changes. After loading or unloading a level that affects walkable surfaces, call
UNavigationSystemV1::Build()or place aNavMeshBoundsVolumethat covers the streamed area and enable Runtime Generation in the project settings. - Lighting: Streamed levels should use pre‑computed lightmaps unless you are using fully dynamic lighting. Heavy static meshes with expensive per‑pixel lighting can cause hitches during load.
- Memory overhead: Each streaming level holds a small descriptor in memory even when unloaded. For dozens of levels this is negligible, but hundreds may add up.
Verifying that streaming works
You can confirm that levels are loading and unloading as expected with built‑in tools:
- Session Frontend: Open Window → Developer Tools → Session Frontend, select the Level Streaming tab, and watch the load/unload events as you trigger your code.
- Console statistics: While playing, press ~ to open the console and type
stat streaming. This shows memory allocated to streamed levels and disk read bandwidth. - Memory report: Run
memreport -fullin the console before and after entering a streamed area. A noticeable drop in used memory after unloading indicates the feature is functioning.
If you see the level’s actors appear only after the OnLevelLoaded callback fires, and the memory statistics reflect the change, the streaming setup is correct.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.