Preload / caching System ? Loading Assets and keep them in Memory

Hi everyone,

We try to implement a preloading System and encounter some Problems. Also its not very clear what Managers and Classes should be used to archive this. In Our Case we have a Application which has around 30GB in .pak data and we want to preload some of this content so we can reduce our Loading times.

Definition:

A Preload / caching System is loading Assets at Runtime into the System Memory before they are needed by the Application so that when needed the Loading times are much faster. This can either be done by blocking the main threat or asynchronous (what we would prefer).

So there are 3 things to do:

  1. Check if we have SystemMemory left
  2. Load Assets from Disk (= a lot of functions and classes can do this, and different Strategies can be applied)
  3. Store them so they don’t get garbagecollected

1) is easy and can be done by:



const FPlatformMemoryConstants& memConstants = FPlatformMemory::GetConstants();


2) There are a couple of places where you can find methodes to load assets:

  • FStreamableManager A native class for managing streaming assets in and keeping them in memory.
  • AssetManager A singleton that is responsible for loading and unloading PrimaryAssets, and maintaining game-specific asset references Games should override this class and change the class reference
  • LoadPackageAsync Asynchronously load a package and all contained objects that match context flags.
  • In addition to that there are various Blueprint Exposed Functions which are able to async load Assets

If you read through the documentation there are a couple of Objects and concepts which are not further explained:

3) You could store Pointers to these Assets into a TMap or Array, with the UPROPERTY() Macro to prevent them from GC.

Questions:

  1. Can Anyone answer what Method to use here ? Or even Further explain the underlying Concept ?
  2. What is a good strategy of loading Assets ? Should you always use .umaps or the “parent” actor so that references are loaded automatically whit them ? Or can you just load all type of assets contained in a Folder as well ?
  3. How to efficiently prevent the loaded Assets from GC ? Also keeping in mind that when finally using the assets they are accessible in a fast way ? Or is this automatically handled by the AssetRegistry or some other System ?

Best
Dominic

P.s. I created an UDN Ticket as well but I dont know when and how it gets exposed to AnswerHub…

What we tried and Problems we encountered: For us it sounded quite Reasonable to use the AssetManager to load data and then Store them in a TMap. But this will fill up our GRam and is ending in a GPU Out of Memory when preloading to much:

.h:



  UPROPERTY()
  TMap<FName, UObject*> cachedObjects;

  TArray<FAssetData> assetData;
  TArray<FString> cachePaths;

 

.cpp function:


  for (const FString& path : cachePaths)
  {
  assetRegistryModule.Get().GetAssetsByPath(FName(*path), assetData, true);
  }

  TArray<FSoftObjectPath> itemsToStream;

  for (int32 i = 0; i < assetData.Num(); ++i)
  {
  itemsToStream.AddUnique(assetData*.ToSoftObjectPath());
  }
  FStreamableDelegate streamableDelegate = FStreamableDelegate::CreateUObject(this, &ThisClass::OnAssetsLoaded);
  assetManager.LoadAssetList(itemsToStream, streamableDelegate);
  }

  void UAVEAssetCache::OnAssetsLoaded()
  {
  for (int32 i = 0; i < assetData.Num(); ++i)
  {
  cachedObjects.Add(assetData*.ObjectPath, assetData*.GetAsset());
  }
  assetData.Empty();
  onAssetsLoadedCallback.Broadcast();
  }
 

I would expect it to fill up the System Memory and will be transfered to GRam as soon as the Renderer needs it…

Were you loading ALL assets ? doing GetAssetsByPath and loading ALL of them with a 30gig pak file sounds like you’re going to run out of memory quick.

You should not load ALL of your assets, you should only load the assets you need at the time.

One of the tricks GTA used back in the day was only load X number of cars, this is why you would always see the player car being driven around even if it was a rare car. This was to limit memory usage. IF they could only load 10 cars at a time and one of the cars was the player controlled cars, then 1 in 10 cars was the same car as the player. Of course they could just reduce the spawn rate even more for that particular car if they didnt want to show it so much. So this would mean in GTA the most cars you would could see at once was 9 cars on the road + 10th being the player car and a small % rare spawn of the player car also being driven around (I dont recall the actual limit GTA used im using 10 arbitrarily).

1 Like

@ We check the SystemMemory how much space is left to not over Fill it. But normally we have 64GB of Memory. In Our Case its an Configurator and the User can load any Data at any given time.

For me its more about what to use to Preload data and load them only to the system Memory and not the GRam.