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