Search Unity

Question How to unload everything currently loaded by Addressables?

Discussion in 'Addressables' started by Peter77, Jun 7, 2021.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    In order to get content updates working, it seems I have to unload everything Addressables related before downloading and integrating the new bundles. Otherwise Unity spits our errors like:
    Code (CSharp):
    1. The AssetBundle 'http://192.168.1.2:59278/xxx_assets_all.bundle'
    2. can't be loaded because another AssetBundle with
    3. the same files is already loaded.
    How can I unload everything that Addressables has currently loaded (release all "filehandles")? I don't want to manually track every asset that's loaded and its dependencies myself and re-implement what Addressables is doing already through "Addressables.ReleaseAsset". It's just not feasible to build such system on top of Addressables in a real-world project.

    Basically what I want to do is this:
    Code (CSharp):
    1. LoadContentUpdateScene(); // does not use any addressable asset, is included in the build itself
    2. ShutdownAllGameSystems();
    3. Addressables.ReleaseAll();
    4. // Addressables.Uninitialize();
    5. // Addressables.Initialize();
    6. DownloadNewContent();
    7. StartupAllGameSystems();
    8. LoadMainMenu();

    Addressables has this information already, so there must be a way to either get the data or even better just unload everything or shutdown Addressables and re-initialize. Every system with an "Initialize" method needs its counter-part method.
     
    Last edited: Jul 31, 2021
    phobos2077 and etopian like this.
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    Unity, do you mind to shed some light here?
    @TreyK-47
     
    etopian likes this.
  3. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,821
    I'll forward to the team for some insight!
     
  4. davidla_unity

    davidla_unity

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    763
    So, we actually have a way to force unique bundle ids for these types of situations. Typically we've heard that if you're doing a content update during your game (as opposed to part of your game/app startup or something) then you might need old content to remain loaded until it was able to complete its lifecycle. Then new references to an asset would use the new bundle. There's some documentation about this here https://docs.unity3d.com/Packages/c...ateWorkflow.html#planning-for-content-updates

    Given the "xxx_assets_all.bundle" bundle name I assume you're using the "filename" bundle naming option on the Content Packing & Loading group schema. You can change that to "append hash" or "hash only" and that should result help alleviate the issue since the updated bundle would have a different name given a changed asset hash.
     
    Peter77 likes this.
  5. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    Thank you for the reply.

    I was looking into Unique Bundle IDs, see here. Unfortunately Unique Bundle IDs cause that bundles change with every build, which wouldn't be that great for a live game. So I better keep it turned off.

    I changed the option for all AssetGroups from "Filename" to "Append Hash to Filename" and keep an eye whether it improved the situation. Thanks for the tip!

    I still think Addressables should provide a way to shutdown. Being able to shutdown Addressables would be quite helpful in real world use-cases for the reasons explained in the initial post.
     
    phobos2077 and Prodigga like this.
  6. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I implemented a hack to release all
    AsyncOperationHandle
    's that are tracked by
    ResourceManager
    . This resolved a ton of content update issues!

    I can't emphasize enough that it'd very useful to provide an
    Addressables.ReleaseAll
    API as explained in the initial post.

    In a perfect world every game would be AsyncOperationHandle leak-free. However, it's easy for such leak to sneak in and it's quite difficult to notice. My project isn't 100% leak-free all the time, some leak sneaks in eventually.

    If such leak exists, content updates fail, which is a severe problem. Much more of a problem than the leak itself.

    I would like you to ask again to officially implement an API to release all operations. It would fix a lot of real-world problems for me and most likely for your other customers too.

    Here is my hack to release all operation handles, which solves a ton of content update issues:
    Code (CSharp):
    1. static List<AsyncOperationHandle> GetAllAsyncOperationHandles()
    2. {
    3.     // Workaround for problems:
    4.     // https://forum.unity.com/threads/how-to-unload-everything-currently-loaded-by-addressables.1121998/
    5.  
    6.     var handles = new List<AsyncOperationHandle>();
    7.  
    8.     var resourceManagerType = Addressables.ResourceManager.GetType();
    9.     var dictionaryMember = resourceManagerType.GetField("m_AssetOperationCache", BindingFlags.NonPublic | BindingFlags.Instance);
    10.     var dictionary = dictionaryMember.GetValue(Addressables.ResourceManager) as IDictionary;
    11.  
    12.     foreach (var asyncOperationInterface in dictionary.Values)
    13.     {
    14.         if (asyncOperationInterface == null)
    15.             continue;
    16.  
    17.         var handle = typeof(AsyncOperationHandle).InvokeMember(nameof(AsyncOperationHandle),
    18.             BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance,
    19.             null, null, new object[] { asyncOperationInterface });
    20.  
    21.         handles.Add((AsyncOperationHandle)handle);
    22.     }
    23.  
    24.     return handles;
    25. }
    26.  
    27. static void ReleaseAsyncOperationHandles(List<AsyncOperationHandle> handles)
    28. {
    29.     foreach (var handle in handles)
    30.     {
    31.         if (!handle.IsDone)
    32.             Dbg.Warning(typeof(ContentUpdateUtility), $"AsyncOperationHandle not completed yet. Releasing anyway!");
    33.  
    34.         while (handle.IsValid())
    35.         {
    36.             Addressables.ResourceManager.Release(handle);
    37.         }
    38.     }
    39. }
    Above code is used like here:
    Code (CSharp):
    1. // Force-releasing all operation handles is a workaround, because if any handle is still acquired,
    2. // Unity refuses to replace these assets with a content update and spits our errors.
    3. // Since it's highly unlikely that we will have a 100% leak free game at all times (and we actually
    4. // never had during my tests), most content updates would fail. This hack fixes a ton of content update issues!
    5. var handles = GetAllAsyncOperationHandles();
    6. ReleaseAsyncOperationHandles(handles);
    7. yield return null;
     
    Last edited: Jul 31, 2021
    hz-him, Toshiza, Claytonious and 8 others like this.