Data Validation Crashing from Running Out Of Memory (OOM)

Hello,

When running data validation on our project, we are running into OOM crashes/issues. Is there a way for the UEditorValidatorSubsystem to programmatically detect low memory and trigger an asset unload pass? Or potentially a way to automatically trigger that after a certain X number of assets? If so, how?

I did see this ticket in the Bug Tracking system Unreal Engine Issues and Bug Tracker (UE-215825). I understand there may not be an official fix out yet, but I wanted to ask if there were any official workarounds that Epic has that we could utilize as we wait for an official solution to be released?

Thank you,

Christina

Hey Christina,

there was actually a changelist submitted recently that includes some logic to unload assets via a new option in the asset validation settings.

This will unload assets individually and not through a GC, but it should work for that case.

The CL is 39298179 in //UE5/Main, or here on Github.

You’ll still need to update the commandlet to set Settings.bUnloadAssetsLoadedForValidation = true.

Let us know if this works out for you, I think it’d be worthwhile to fix the commandlet on our side to enable that by default.

Kind Regards,

Sebastian

There’s indeed CL39299978 (Github) that was submitted shortly after and might be relevant.

The description says “Fix trying to load external actors on a non-partitioned world or on a validation task with no external objects.”, this sounds like it might apply to your crash.

If that doesn’t help either it might help to build UE5/main from source and check in a copy of your project if this works in Main, there’s always a chance that these CLs depend on other changes made since 5.4 and can’t be integrated easily.

Hey Christina,

apologies for the delay, I’ve been OOO the last week.

As for the slowdown, this might be related to the fact that immediately unloading assets could lead to them being repeatedly loaded and unloaded, thus introducing a lot of extra overhead.

I’m talking to the original developer of the bUnloadAssetsLoadedForValidation switch to understand the intended use-case better, it likely wasn’t intended for bulk validation and is very inefficient for this case.

Could you run the commandlet with the -tracefile -trace=default,task -statnamedevents and attach the resulting trace here (should be in Saved/Profiling in your project directory)?

It’s probably enough to let it run for 10 minutes or so to get an idea of where the runtime is going.

Overall this solution is probably not suited well for bulk runs.

At Epic we try to push the validation to save time, so that validates happen either when saving an asset or when submitting it through source control. This way all assets that are submitted should have been validated. This reduced the need for big automated bulk validations that run on the whole project.

As another possible workaround you could try to limit the validation to certain parts of your content, so that each individual run needs less memory to run. That also has the additional advantage of allowing you to do different validation frequencies for different content.

As for your other question:

> how does Unreal manage the UObjects for the loaded assets? Is there something that explicitly keeps them and their related content “rooted” to avoid their being garbage collected during validation?

There are different approaches in Editor, the game and commandlets.

For the game the intention is that all UObjects are garbage collected and garbage collection happens in a regular interval and finds and deletes all objects that are no longer referenced by anything else and thus orphaned.

In the Editor all the assets that are loaded are indeed “rooted”, or added to the root set, a global list of objects that should never be unloaded by the GC. This can be done by calling Object->AddToRoot() and RemoveFromRoot() in C++. This prevents regular assets from being unloaded in the Editor by default. This is mostly done as an optimization to improve loading and PIE times.

Commandlets are slightly different again, because by default they don’t run the GC at all, since there is no Engine ticking in commandlets. It is the responsibility of the commandlet author to initiate GC when necessary and unfortunately most of our commandlets are fairly old and don’t have any logic for these cases. This has only begun to be a problem with much larger games and content sizes.

Kind Regards,

Sebastian

Hi Sebastian,

Thanks for the response! When running validation with these changes you provided, I ended up hitting a crash due to InWorld->GetWorldPartition() being null in LoadExternalObjectsForValidation.cpp (line 38 of the Github link you provided). I added a check to verify that GetWorldPartition() is valid before calling FindContainer(). However, while this allowed DataValidation to run for longer, I ended up hitting another crash also due to a read access violation (different from the original crash I was hitting in my original post). Do you know if this was something y’all also ran into and fixed in a later CL that wasn’t captured in the one you provided? If so, would you be able to provide those changes for me to try out?

Thanks,

Christina

Hey Sebastian,

Thanks for the link to that CL on GitHub, it helped me get past the issue I was having. However, I notice that with these changes, running data validation takes much longer than usual. Our usual times are about 20-30 minutes, and with these changes, the time spiked up to 2hr 49m, give or take (I’ve ran it a couple times to confirm, they were all around almost 3hrs). Is the extra time that data validation takes with these changes implemented expected? If so, do you have any suggestions on how to unload assets in a quicker manner?

Thanks,

Christina

Hi again -- I have an additional question: how does Unreal manage the UObjects for the loaded assets? Is there something that explicitly keeps them and their related content “rooted” to avoid their being garbage collected during validation?

Thanks!