Spring Sale: 30% off bundles with SPRINGBUNDLE or 15% off individual products with SPRING15 — ends Apr 15

StraySparkStraySpark
ProductsFree AssetsDocsBlogGamesAbout
StraySparkStraySpark

Game Studio & UE5 Tool Developers. Building professional-grade tools for the Unreal Engine community.

Products

  • Complete Toolkit (Bundle)
  • Procedural Placement Tool
  • Cinematic Spline Tool
  • Blueprint Template Library
  • DetailForge
  • UltraWire
  • Unreal MCP Server
  • Blender MCP Server
  • Godot MCP Server

Resources

  • Free Assets
  • Documentation
  • Blog
  • Changelog
  • Roadmap
  • FAQ
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 StraySpark. All rights reserved.

Back to Blog
tutorial
StraySparkMarch 22, 20265 min read
UE5 Memory Optimization: Asset Streaming, Soft References, and World Partition 
Unreal EngineOptimizationPerformanceMemoryStreaming

Memory Is the Silent Killer

Frame rate gets all the attention, but memory is what silently kills UE5 projects. You won't notice the problem during development — your 64GB workstation handles everything fine. Then players on 16GB machines crash to desktop, and you're scrambling to figure out what went wrong.

Memory optimization isn't glamorous, but it's essential for shipping on platforms with tight memory budgets: consoles (unified memory), Steam Deck (16GB shared), and minimum-spec PCs.

Understanding UE5 Memory Usage

Where Memory Goes

A typical UE5 game's memory breakdown:

CategoryTypical UsageNotes
Textures2-8 GBLargest consumer, streamable
Meshes (Non-Nanite)0.5-2 GBLOD levels, collision
Nanite Data0.5-3 GBVirtualized geometry
Audio0.2-1 GBDecompressed audio in memory
Blueprints/Code0.5-1 GBCompiled Blueprint bytecode
Physics0.1-0.5 GBCollision data, physics state
Navigation0.1-0.5 GBNavMesh data
Particles0.1-0.5 GBNiagara system data
Engine Overhead1-2 GBUObject system, GC, framework

Monitoring Memory

stat memory           // High-level memory overview
stat memoryplatform   // Platform-specific breakdown
memreport -full       // Detailed report to log file
stat streaming        // Texture/mesh streaming status
obj list              // All loaded UObjects with sizes

For detailed analysis, use Unreal Insights with the memory trace channel:

UnrealEditor.exe YourProject.uproject -trace=memory,default

Hard References vs Soft References

This is the single most impactful memory concept in UE5.

Hard References

A hard reference loads the referenced asset when the referencing object loads:

// Hard reference — BP_Enemy loads when THIS Blueprint loads
UPROPERTY(EditDefaultsOnly)
TSubclassOf<AActor> EnemyClass;

// Hard reference — texture loads with this material
UPROPERTY(EditDefaultsOnly)
UTexture2D* DiffuseTexture;

If your main menu Blueprint hard-references your level's boss enemy, which hard-references its weapon, which hard-references explosion particles, which hard-reference destruction meshes... loading the main menu loads all of that into memory.

This is called reference chain bloat, and it's the #1 memory problem in UE5 projects.

Soft References

A soft reference stores the asset path without loading it:

// Soft reference — does NOT load automatically
UPROPERTY(EditDefaultsOnly)
TSoftClassPtr<AActor> EnemyClass;

UPROPERTY(EditDefaultsOnly)
TSoftObjectPtr<UTexture2D> DiffuseTexture;

Load soft references when you actually need them:

void AEnemySpawner::SpawnEnemy()
{
    if (EnemyClass.IsNull()) return;

    // Async load — doesn't block the game thread
    FStreamableManager& Streamable = UAssetManager::GetStreamableManager();
    Streamable.RequestAsyncLoad(EnemyClass.ToSoftObjectPath(),
        FStreamableDelegate::CreateUObject(this, &AEnemySpawner::OnEnemyClassLoaded));
}

void AEnemySpawner::OnEnemyClassLoaded()
{
    UClass* LoadedClass = EnemyClass.Get();
    if (LoadedClass)
    {
        GetWorld()->SpawnActor<AActor>(LoadedClass, SpawnTransform);
    }
}

The Rule

Use hard references for assets that are always needed (base character mesh, core UI textures, frequently used materials).

Use soft references for everything else — enemies, weapons, level-specific assets, optional content, cosmetics.

Finding Reference Chain Problems

Use the Reference Viewer (right-click any asset → Reference Viewer) to visualize dependency chains. Look for:

  • Assets referenced from many places (potential for unnecessary loading)
  • Long chains that pull in unrelated content
  • Large assets (textures, meshes) referenced by small objects (data tables, configs)

The Size Map tool (Window → Developer Tools → Size Map) shows the total memory footprint of an asset including all its dependencies.

Texture Streaming

How It Works

UE5 streams textures at runtime, loading only the mip levels needed for the current view:

  • A texture 50 meters away loads a low-resolution mip (512x512)
  • As the camera approaches, higher mips stream in (1024, 2048, 4096)
  • Distant textures drop to lower mips to free memory

Streaming Pool Configuration

The Texture Streaming Pool is a fixed-size memory budget for streamed textures:

; DefaultEngine.ini
[/Script/Engine.RendererSettings]
r.Streaming.PoolSize=1000  ; Pool size in MB

Sizing the pool:

  • Minimum spec PC (8GB RAM): 512-768 MB
  • Mid-range PC (16GB): 1000-1500 MB
  • High-end PC / Console: 1500-2500 MB
  • Steam Deck: 512-768 MB

If the pool is too small, textures visibly pop in as blurry-to-sharp. If too large, it steals memory from other systems.

Texture Optimization

  • Max texture size: Most textures don't need 4096x4096. Set per-texture max size in the texture editor
  • Compression: Use BC7 for quality, BC1/BC3 for size-sensitive textures
  • Virtual Textures: For landscape and large-surface materials, virtual textures stream tiles instead of mips
  • Texture groups: Assign textures to groups (World, Character, UI, Effects) with per-group streaming settings
  • Never Stream flag: Only set for textures that must be fully loaded (UI, critical effects)

World Partition

For open-world games, World Partition is essential for memory management.

How It Works

World Partition divides your level into a grid of cells. Only cells near the player are loaded — everything else is streamed out.

Setting Up World Partition

  1. In Level Settings, enable World Partition
  2. Set Cell Size: 12800-25600 units is typical (128-256 meters)
  3. Set Loading Range: How far from the player cells load (usually 2-3x cell size)
  4. Place actors — they're automatically assigned to cells based on position

Streaming Configuration

; Per-actor streaming distance override
bOverrideWorldPartitionLoadingRange=True
LoadingRange=50000  ; Override for specific actors like landmarks

Loading range by actor type:

  • Terrain/Landscape: Match view distance (50,000+ units)
  • Large buildings: 30,000-50,000 units
  • Trees/Foliage: 15,000-30,000 units
  • Small props: 5,000-15,000 units
  • Ground clutter: 3,000-5,000 units

HLOD (Hierarchical Level of Detail)

For cells that are loaded but distant, HLOD provides simplified representations:

  • HLOD0: Simplified meshes for medium distance
  • HLOD1: Even simpler (merged) meshes for far distance
  • HLOD2: Impostor/billboard for extreme distance

Configure HLOD layers in World Partition settings. Build HLODs before shipping.

Asset Manager and Primary Asset Types

For large projects, the Asset Manager provides fine-grained control over asset loading:

// Register primary asset types in DefaultGame.ini
[/Script/Engine.AssetManagerSettings]
+PrimaryAssetTypesToScan=(PrimaryAssetType="Map", AssetBaseClass=/Script/Engine.World, ...)
+PrimaryAssetTypesToScan=(PrimaryAssetType="EnemyData", AssetBaseClass=/Script/MyGame.UEnemyDataAsset, ...)

Then load asset bundles on demand:

// Load all assets for "Level_Forest" bundle
FPrimaryAssetId LevelAssetId = FPrimaryAssetId("Map", "Level_Forest");
UAssetManager::Get().LoadPrimaryAsset(LevelAssetId,
    {"Visual", "Gameplay"},
    FStreamableDelegate::CreateLambda([this]() {
        // Assets loaded, safe to use
    }));

Garbage Collection

UE5's garbage collector runs periodically to clean up unreferenced UObjects. Understanding GC helps avoid memory leaks:

Common Leak Patterns

Leaked references: Holding a UPROPERTY pointer to an object prevents GC from collecting it, even after the object is logically "destroyed."

// This leaks if the spawned actor is destroyed but SpawnedEnemy still holds a reference
UPROPERTY()
AActor* SpawnedEnemy;

// Fix: Null the pointer when the actor is destroyed
SpawnedEnemy->OnDestroyed.AddDynamic(this, &ASpawner::OnEnemyDestroyed);
void ASpawner::OnEnemyDestroyed(AActor* Actor) { SpawnedEnemy = nullptr; }

TArray of UObject pointers: Growing arrays that never shrink hold references indefinitely. Clear arrays when done.

Delegates: Bound delegates prevent GC of the bound object. Always unbind in EndPlay/BeginDestroy.

GC Tuning

; Increase GC frequency for memory-constrained platforms
gc.TimeBetweenPurgingPendingKillObjects=30  ; Seconds between GC runs (default: 60)
gc.MaxObjectsNotConsideredByGC=1            ; Force GC to check all objects

Memory Budget Planning

Before building content, set memory budgets:

CategoryBudget (16GB target)
OS + Drivers2-3 GB
Engine Overhead1.5 GB
Texture Streaming Pool1 GB
Meshes + Nanite1.5 GB
Audio0.5 GB
Gameplay Objects1 GB
Physics + Navigation0.5 GB
Headroom1-2 GB
Total Available~10-12 GB

Track actual usage against budgets weekly. Catching memory creep early is infinitely easier than fixing it before launch.

Quick Wins

  1. Audit hard references: Use the Reference Viewer on your most-loaded Blueprints. Convert unnecessary hard refs to soft refs.
  2. Set texture max sizes: Most environment textures don't need 4096. Set to 2048 or 1024 where quality allows.
  3. Enable texture streaming: Ensure r.Streaming.PoolSize is set appropriately and textures aren't marked "Never Stream" unnecessarily.
  4. Use World Partition: If your game has levels larger than 500m, World Partition saves memory automatically.
  5. Profile on target hardware: Your dev machine hides memory problems. Test on minimum spec early and often.

Memory optimization is ongoing work, not a one-time task. Build awareness of memory usage into your development habits, and your game will run smoothly on the hardware your players actually own.

Tags

Unreal EngineOptimizationPerformanceMemoryStreaming

Continue Reading

tutorial

Getting Started with UE5 PCG Framework: Build Your First Procedural World

Read more
tutorial

Nanite Foliage in UE5: The Complete Guide to High-Performance Vegetation

Read more
tutorial

UE5 Lumen Optimization Guide: Achieving 60fps with Dynamic Global Illumination

Read more
All posts