Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug LoadAssetAsync doesnt work for a minute on start but then is always almost instant

Discussion in 'Addressables' started by manubare, Jun 7, 2023.

  1. manubare

    manubare

    Joined:
    Sep 12, 2019
    Posts:
    7
    Hello, Im new to addressables as I recently started using them to load assets on demand from a list of over 1000 of them.

    On editor they load instantly but on build it takes a solid minute before LoadAssetAsync calls do anything. Then once the time has passed, Unity will "resume" and execute all new LoadAssetAsync almost instantly.

    Here's the code:

    Code (CSharp):
    1.  
    2.         public void LoadAsset()
    3.         {
    4.             if (loadingAsset || assetReady) { return; }
    5.  
    6.             Debug.Log($"<color=olive>LoadAsset {this}</color>");
    7.             AssetPrefabLoadManager.NewLoadingData(this);
    8.             Addressables.LoadAssetAsync<GameObject>(assetRef).Completed +=
    9.             (asyncOperationHandle) =>
    10.             {
    11.                 if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
    12.                 {
    13.                     Debug.Log($"<color=green>loaded {this}</color>");
    14.                     AssetPrefabLoadManager.AddEntry(this, asyncOperationHandle.Result());
    15.                     AssetPrefabLoadManager.RemoveLoadingData(this);
    16.                 }
    17.             };
    18.         }
    Some of these assets I call on the first few frames of the program and I yet it takes forever to complete. Then minutes will pass and I execute the same method on another asset and it will load in a second.
    Im doing these calls in batches of 20. So first I will load 20 assets (which will take forever) and after that I will load another 20 which is real fast. No matter which assets I load this will always happens, its not a problem with the first 20 assets.

    Each asset is a basic lowpoly 3D model with 3 HD textures. AFAIK this shouldnt be an issue. Its also not a specific problem with a set asset. This will happen with all of them.

    Help I have no clue how else to debug this issue.
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,606
    Most likely they load instantly in the editor, because, by default, addressables loads via asset database. In the addressables groups window, there's a 'Play Mode Script' dropdown which you can change it to simulate groups, or use the existing built addressables groups.

    Beyond that, when addressables is first called it has to initialise. So in some situations you may want to manually initialise it with with
    Addressables.InitialiseAsync()
    . Do not that addressables won't work until you've completely loaded into the first scene of your application.

    Speaking of async, your loading method is a bit odd in that it's completely blocking, and isn't blocking in the suggested manner by using
    .WaitForCompletion()
    . You should do something like this:
    Code (CSharp):
    1. var handle = Addressables.LoadAssetAsync<GameObject>(assetRef);
    2. handle.WaitForCompletion();
    3. if (handle.Status == AsyncOperationStatus.Succeeded)
    4. {
    5.     Debug.Log($"<color=green>loaded {this}</color>");
    6.     AssetPrefabLoadManager.AddEntry(this, asyncOperationHandle.Result());
    7.     AssetPrefabLoadManager.RemoveLoadingData(this);
    8. }
    Though I would suggest loading asynchronously via a coroutine or regular C# async as well.
     
  3. manubare

    manubare

    Joined:
    Sep 12, 2019
    Posts:
    7
    Thanks for the response!

    I went ahead and modified the code so that the loading screen waits for the addressables to initialise like this:

    Code (CSharp):
    1.  
    2.             AsyncOperationHandle<IResourceLocator> handle = Addressables.InitializeAsync();
    3.             yield return handle;
    And also modifier the load method so that it works as a coroutine as you suggested:

    Code (CSharp):
    1.  
    2.         private IEnumerator LoadAssetAsync()
    3.         {
    4.             AssetPrefabLoadManager.NewLoadingData(this);
    5.             var handle = Addressables.LoadAssetAsync<GameObject>(assetRef);
    6.             yield return handle;
    7.             if (handle.Status == AsyncOperationStatus.Succeeded)
    8.             {
    9. #if UNITY_EDITOR
    10.                 Debug.Log($"<color=green>loaded {this}</color>");
    11. #endif
    12.                 AssetPrefabLoadManager.AddEntry(this, handle.Result.GetComponent<CBAsset>());
    13.                 AssetPrefabLoadManager.RemoveLoadingData(this);
    14.             }
    15.         }
    However the wait time remains more or less the same.
    I should also add that all of these are more than 1000 assets and all part of the same addressables group, which might impact performance? Im unsure if splitting them into other groups would be better tho.

    The 'Play Mode Script' dropdown came in very handy as now Im able to replicate the exact issue that happens on build by using the "use existing build" option.
    As you can see here, the initialization is called way ahead but the load times are still way too much
    cc632bf2799e0c37eb413d3709cbb0b3.png

    On the other hand, after the first batch is loaded, all consecutive ones are super quick:
    5876283e6e7ba2738544f3f4da516b42.png
     
  4. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    970
    This is not correct. Registering a Completed handler is not blocking, it is one of the standard non-blocking ways of loading via the addressables system.
     
    spiney199 likes this.
  5. manubare

    manubare

    Joined:
    Sep 12, 2019
    Posts:
    7
    Small bump cause I cant find nothing online to solve this problem.
    The initialization process still takes forever. This is all for addressables that are stored locally too.
    So far I've tried:

    - Disables catalog update on startup: I dont need to change my catalog.
    - Calling Addressables.InitializeAsync() right as the program starts, so there's time for those to load while the player moves through the main menu and loading screens.
    - Disabled Build remote catalog: As its all local.
    - Addressables assetbundle is uncompressed: Faster load time.
    - Use UnityWebRequest for local asset bundles > true: Read online that for some people this really speed up the process.

    Despite all of this, Im still sitting at an average initialize time of 1 minute. After which, all addressable calls will be executed almost instantly.
     
  6. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    970
    Hm, this is really odd. You may need to embed the package and add some debug logging.
     
  7. unity_shane

    unity_shane

    Unity Technologies

    Joined:
    Jun 3, 2021
    Posts:
    106
    @manubare,

    Hi there, I think the issue likely has to do with the fact that all of your assets are loaded into a single asset bundle (is this correct? This is generally the case if everything is in a single addressables group, although if you are using Pack Separately or Pack Separately by Label, this may not be the case).

    The way that addressables works is the following: When you try and do a load for an assetbundle that is not in memory, it will first load that assetbundle into memory - this operation has some amount of overhead, and the bigger the assetbundle, the greater this overhead will be. Once the assetbundle is loaded into memory, all subsequent loads will then be done by loading the asset directly from the assetbundle, which is now in memory.

    If I had to guess, what is happening is that on your first load, addressables has to take some time to load your assetbundle (which is extremely large), but once that assetbundle is loaded, everything else is fast. There's a couple ways around this:

    1. You could separate your assets into smaller assetbundles based on one of the recommended bundling strategies from the Unity docs (as a note - do not use type grouping, it usually will result in very poor performance, among other things). While it will require some work to determine what asset should go in which assetbundle to make sure everything is loaded at appropriate times without extensive dependencies between the assetbundles, this will almost certainly dramatically reduce the amount of time your first load takes.
    2. You could, as part of your load screen, do your first call to LoadAssetAsync. This way, during your loading screen you will be loading the assetbundle into memory, and after this point everything will be fast. This of course has the cost of making your loading screen longer, so it may not be an ideal option.

    Generally, I would recommend strategy 1 unless you are very close to shipping your game - ultimately one of the benefits of the addressables system is being able to load and unload your assetbundles dynamically so as to manage your memory usage. By having everything in a single assetbundle, you will essentially constantly have all of your assets that you load in memory for the entire life of your application, which is often not ideal. For more information about memory management in addressables, you can check out our docs page here. I hope this helps!