DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Singleton: 6 Ways To Write and Use in Java Programming
  • Shallow and Deep Copies in JavaScript: What’s the Difference?
  • Using Regular Expressions in Python: A Brief Guide
  • How to Estimate Object Memory Allocation in Java

Trending

  • How My AI Agents Learned to Talk to Each Other With A2A
  • Software Specs 2.0: An Elaborate Example
  • Stabilizing ETL Pipelines With Airflow, Presto, and Metadata Contracts
  • Docker Model Runner: Running AI Models Locally Made Simple
  1. DZone
  2. Coding
  3. Languages
  4. Dealing With Memory Leaks in Unreal Engine 4

Dealing With Memory Leaks in Unreal Engine 4

Memory leaks are difficult to remedy. Here are techniques which you can follow along with to track down the source of your memory leaks.

By 
Cody Albert user avatar
Cody Albert
·
May. 22, 16 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
11.0K Views

Join the DZone community and get the full member experience.

Join For Free

Memory leaks are an elusive category of bugs that often take quite a while to manifest. These bugs occur when we allocate memory for something and then lose track of it without ever freeing up the memory it’s using. Memory leaks contribute to overall instability, causing an application to get bogged down and eventually crash as it slowly consumes all of the available RAM. 

While it’s hard to patch up every leaky allocation, there are a few techniques we can use to find the largest offenders and make sure they stop hogging memory that they don’t need. Recently, the Paragon team did just that in response to some memory leaks that would crash the game after a few hours. While Paragon matches rarely last long enough to eat up all of the system's memory, it’s difficult to predict how the match may play out. After all, nothing would be more frustrating than having your client crash right as your team engages in that pivotal team fight!

Finding Evidence of Leaks With MemReport

The first step to tracking down memory leaks is determining whether or not a leak is occurring. A simple way to do this is to take a snapshot of the current memory allocations at two different points in time, and comparing them to see what has changed. If no actions are taken in the game, we can expect similar memory usage regardless of the amount of time passed. However, if there is a steady rise in the amount of memory used as time passes, it may be time to start looking for a leak.

As an example, I created an Actor that allocated 1,000 integers per Tick, throwing away the reference immediately. I dropped my Actor in an empty scene and allowed it to run for ten minutes, and took a MemReport at the beginning and end of my session. A comparison of the two reports shows a noticeable increase in memory usage, despite the fact that the object count hasn’t changed at all.

Leaks

More information about MemReport can be found in a previous blog post, Debugging and Optimizing Memory.

MemReport can help distinguish memory leaks from other types of leaks, such as object leaks. An object leak may be occurring if the number of objects present in the scene is consistently increasing. This typically indicates that spawned objects aren’t being cleaned up properly. For example, what if we create a projectile class that is destroyed when colliding with another object? Projectiles fired into the air will just travel skyward forever, holding on to valuable memory.  The MemReport will show how many instances of each object exist in the world at that time, giving a clue as to which object is leaking so that we can investigate the spawning and despawning logic to see if there’s a problem.

Open Allocations

Once we suspect some of our memory allocations are never being freed, we need to track down who is responsible for those allocations. To accomplish this, the Paragon team built a tool that can monitor any open memory allocations that haven’t yet been freed. The tool is still experimental and disabled by default, so you’ll need to make a quick change to MallocLeakDetection.h and recompile:

#define MALLOC_LEAKDETECTION 1

Once you’ve done that, make sure you have Visual Studio running and attached to your game instance. You can begin logging by typing “MallocLeak Start” in the console and stop by typing “MallocLeak Stop”. The tool will then dump all open allocations that were made during the logging period into Visual Studio’s output window. Optionally, you can type “MallocLeak Dump N” while the logger is running, where N is a size in bytes. This will immediately dump open allocations filtered to allocations of at least N bytes. It’s helpful to begin logging after the game has initialized, as many allocations may be made at initialization and not freed until the game is closed. 

I modified my leaky Actor to make a large allocation 10 seconds after the game starts. I then ensured MallocLeak was running during the allocation, and used “MallocLeak Dump 1000000” to dump all open allocations larger than 1 megabyte. As expected, I found something suspicious in the results. Quite a bit of memory has been allocated by an Actor’s Tick function!

AllocSize: 12345678, Num: 1, FirstFrameEverAllocated: 1522
  UE4Editor-Core.dll!FWindowsPlatformStackWalk::CaptureStackBackTrace()
 [d:\release-4.11\engine\source\runtime\core\private\windows\windowsplatformstackwalk.cpp:233]
  UE4Editor-Core.dll!FMallocLeakDetection::Malloc()
 [d:\release-4.11\engine\source\runtime\core\private\hal\mallocleakdetection.cpp:180]
  UE4Editor-Core.dll!FMallocLeakDetectionProxy::Malloc()
 [d:\release-4.11\engine\source\runtime\core\private\hal\mallocleakdetection.h:116]
  UE4Editor-MemoryLeak.dll
  UE4Editor-Engine.dll!AActor::TickActor()
 [d:\release-4.11\engine\source\runtime\engine\private\actor.cpp:807]
  UE4Editor-Engine.dll!FActorTickFunction::ExecuteTick()
 [d:\release-4.11\engine\source\runtime\engine\private\actor.cpp:111]
  UE4Editor-Engine.dll!FTickFunctionTask::DoTask()
 [d:\release-4.11\engine\source\runtime\engine\private\ticktaskmanager.cpp:262]
  UE4Editor-Engine.dll!TGraphTask<FTickFunctionTask>::ExecuteTask()
 [d:\release-4.11\engine\source\runtime\core\public\async\taskgraphinterfaces.h:999]
  UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksNamedThread()
 [d:\release-4.11\engine\source\runtime\core\private\async\taskgraph.cpp:932]
  UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksUntilQuit()
 [d:\release-4.11\engine\source\runtime\core\private\async\taskgraph.cpp:679]
  UE4Editor-Core.dll!FTaskGraphImplementation::WaitUntilTasksComplete()
 [d:\release-4.11\engine\source\runtime\core\private\async\taskgraph.cpp:1776]
  UE4Editor-Engine.dll!FTickTaskSequencer::ReleaseTickGroup()
 [d:\release-4.11\engine\source\runtime\engine\private\ticktaskmanager.cpp:530]
  UE4Editor-Engine.dll!FTickTaskManager::RunTickGroup()
 [d:\release-4.11\engine\source\runtime\engine\private\ticktaskmanager.cpp:1435]
  UE4Editor-Engine.dll!UWorld::RunTickGroup()
 [d:\release-4.11\engine\source\runtime\engine\private\leveltick.cpp:704]
  UE4Editor-Engine.dll!UWorld::Tick()
 [d:\release-4.11\engine\source\runtime\engine\private\leveltick.cpp:1197]
  UE4Editor-UnrealEd.dll!UEditorEngine::Tick()
 [d:\release-4.11\engine\source\editor\unrealed\private\editorengine.cpp:1346]
  UE4Editor-UnrealEd.dll!UUnrealEdEngine::Tick()
 [d:\release-4.11\engine\source\editor\unrealed\private\unrealedengine.cpp:368]
  UE4Editor.exe!FEngineLoop::Tick()
 [d:\release-4.11\engine\source\runtime\launch\private\launchengineloop.cpp:2772]
  UE4Editor.exe!GuardedMain()
 [d:\release-4.11\engine\source\runtime\launch\private\launch.cpp:148]
  UE4Editor.exe!WinMain()
 [d:\release-4.11\engine\source\runtime\launch\private\windows\launchwindows.cpp:189]
  UE4Editor.exe!__scrt_common_main_seh()
 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264]
  kernel32.dll
  ntdll.dll

As with most profiling techniques, it’s important to look at the results critically. Keep in mind that allocations made before you begin logging won’t show up in the result. Similarly, allocations freed after you stop logging will show up, even if they aren’t indicative of a leak. However, the MallocLeak tool is great for investigating where your memory is going and give some hints as to where to look for the offending code. Happy Hunting!

Memory (storage engine) Unreal Engine Game engine Object (computer science) Engine

Published at DZone with permission of Cody Albert. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Singleton: 6 Ways To Write and Use in Java Programming
  • Shallow and Deep Copies in JavaScript: What’s the Difference?
  • Using Regular Expressions in Python: A Brief Guide
  • How to Estimate Object Memory Allocation in Java

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: