Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Addressables unloading dependencies from other assets.

Discussion in 'Addressables' started by KAJed, May 20, 2020.

  1. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    I am using Addressables 1.8.3 and having an issue where unloading some assets causes other dependencies to become unloaded. This applies to things such as materials as well as ScriptableObjects.

    Just about everything is marked as addressable. I gather depedencies and try to ensure that no asset duplication happens (it works in a similar fashion to the asset de-duplication analysis). Every single asset in my game except for the bootstrapped scene is loaded through addressables (and are in fact bundles).

    However, despite this, it seems as though unloading assets breaks some non-addressable referenced data. So if that piece of data (material, SO, whatever) is just a plain reference it has a good chance of becoming null as the bundle that that data is actually in gets unloaded. That asset itself is also addressable even though in this particular case I'm not using it as one (it's only marked to eliminate duplication).

    It almost seems like the dependency check in the addressables is incomplete? Has anyone else had this happen? Solutions? Suggestions?
     
    anycolourulike and Xarbrough like this.
  2. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,799
    I'll kick this over to the team to provide some guidance.
     
    KAJed likes this.
  3. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    anycolourulike and andreiagmu like this.
  4. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,799
    Team wanted me to pass along that they have been seeing others reporting this, and it's on their radar. They also suggested you file a bug report with your project attached so they can look into it further: https://unity3d.com/unity/qa/bug-reporting
     
  5. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    @TreyK-47 I am not in a position to be able to attach a project nor create a minimal reproduction project. Which is usually where Unity bugs get pushed to "can't fix, no reproduction". This issue is very similar to the issues arising from the DontDestroyOnLoad issues mentioned in 1.9.2 except it applies to everything not just those. DontDestroyOnLoad assets just happen to be one way that it can occur.
     
  6. Thermos

    Thermos

    Joined:
    Feb 23, 2015
    Posts:
    148
    Load a scriptableObject which direct reference to another addressable audio clip(in another group only contains audio clips referenced by scriptableObjects), unload this scriptableObject, call Resouces.UnloadAllUnsuedAssets, Load this scriptableObject again, audio clip is missing. To me this happens 100% in my project, my solution is simple, hold a reference to a random audio clip in that group and never release it.....
     
    KAJed likes this.
  7. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    @Thermos That's the thing - it can be solved by bundling differently as well. But, since that is difficult to do well I think it would make more sense for them to fix it on the addressables end as people will run in to this eventually.

    In theory it should be solvable by making sure that dependencies are coalesced when loaded from a bundle. That is: if you load one object from a bundle, and another object from a bundle - technically those two objects may now share cross bundle dependencies because objects cannot be unloaded properly except by unloading a whole bundle.
     
  8. jannysice

    jannysice

    Joined:
    Jun 8, 2017
    Posts:
    11
    Was able to get a reproduce with a small test project. Submitted a bug report. Case number 1266005 .
    It has to do with indirect bundle dependencies:

    Lets assume there are three bundles. A, B and C.
    A depends on B and B depends on C.
    Note: A does NOT depend on C directly.

    So lets say we do:

    1. Load an asset of A
    This will also load B because A depends on B

    2. Instantiate a prefab of B that references an asset in C
    This will also load C because B depends on C

    3. Release the instance of prefab B
    This will unload C but it will NOT unload B because an asset of A is still loaded, which has a dependency on B

    4. Instantiate the prefab of B again. Now the reference on prefab B to the asset in C is missing.
     
    Ultroman, andre_unity573 and KAJed like this.
  9. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    Yep. This is why they need to properly track dependencies for entire bundles and not just individual objects which seems to be the underlying issue.
     
    andre_unity573 likes this.
  10. andre_unity573

    andre_unity573

    Joined:
    Oct 17, 2018
    Posts:
    34
    It seems we were having the same issue here, our materials were losing reference to the textures after unloading the prefabs through Addressables and loading them again.
    My interpretation would be that, like in the example from @jannysice, We had a bundle for the prefab (A), another for the material (B) and another for the texture (C). When loading the assets a second time after releasing them, the material (B) would lose reference to the texture (C)...

    Here we tried to workaround this issue by replacing the "AssetBundleProvider" built-in script in every group for a custom one that would force the internal AssetBundle.Unload() call parameter to "false" (that way it will only unload the bundle but not the assets), and then forcing a Resources.UnloadUnusedAssets() between the scenes loading.
    At first it seemed to work, memory still seemed to be stable from one scene to another, although some assets would stay in memory until a second scene loading, but then later we started have what seems to be memory fragmentation issues in console platforms and we are struggling with it right now...

    It is just frustrating that we are having so much trouble to implement such simple scenario. We had no problems to adapt the code to work asynchronously, but instead we are having such weird dependency issues...
     
    anycolourulike and Xarbrough like this.
  11. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    Yes. They absolutely need to fix the issue. The solution could mostly involve baking more metadata per asset which might increase the footprint.
     
  12. andre_unity573

    andre_unity573

    Joined:
    Oct 17, 2018
    Posts:
    34
    @KAJed, @jannysice and @Thermos, it seems the latest version, 1.13.1, fixed the issue for us, you should check it out if you didn't.
     
  13. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    959
    Interestingly enough, we have a similar situation occurring that is not fixed by 1.13.1. It was an absolute mess to diagnose but it boils down to something along the lines of:

    Addressable asset A is packed separately with its dependencies in bundle a. It also depends on assets from common dependency bundle b.
    Addressable asset C is packed separately with its dependencies in bundle c. It also depends on assets from common dependency bundle b.

    Load assets A and C, which loads bundles a, b, and c.
    Unload asset A but retain asset C.
    Resources.UnloadUnusedAssets();
    Reload bundle A and its dependencies fail to resolve, dropping back to null or, more confusingly, losing their type back to UnityEngine.Object, even though the bundle should not have been unloaded since its reference count is > 0.

    In our case this was caused because our code was occasionally leaking asset C, which I have fixed (i.e. refactored out of existence...) but the underlying issue seems to remain that "loaded" asset bundles are basically unloaded.
     
    andre_unity573 likes this.
  14. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    They do make note of some changes in the change log. I'll have a look. Thanks!
     
  15. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    Oh a new caveat I didn't previously know (somewhat unrelated to all this). You cannot call ReleaseInstance from Awake or OnEnable. They will fail to release the ref count. It is safe from Start though!
     
  16. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    @TreyK-47 and anyone else here interested. If you haven't noticed Unity did fix the problem. Assets are no longer unloaded when they shouldn't be. However, because the fix was to precompute all bundle dependencies I highly recommend anyone using them have a look at their dependencies in the event viewer. For my current project the result is that many bundles can no longer ever be unloaded because of the precomputed dependencies. You have to be even more diligent than before to ensure that your bundles are not directly connected (that is: everything must be AssetReferences).

    Effectively their solution is forcing us to do exactly what I mentioned previously: you have to put AssetReference everywhere and this can be a massive undertaking. The reason the fix works, and why it is working as such (since the wording "Expanded bundle dependencies so that loaded bundles maintain a reference to all bundle they references. This fixes various bugs when unloading and reloading a bundle that is being referenced by another bundle." is a bit misleading) is that if you point at any one thing in a bundle now it points at all things in the bundle. This causes the bundle dependency chain to grow a lot.
     
  17. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    959
    There are ways to manage long dependency chains without losing automatic dependency tracking by having to use AssetReference everywhere.

    What we have is:
    Groups with loads of assets representing individually loadable items in the game. Each is a scriptable object with loads of references to other assets. Loads of these assets have shared dependencies, sometimes several bundles deep.
    We run a custom version of the Check Duplicate Bundle Dependencies rule, which extracts all common dependencies into a local and a remote dependency isolation group. These groups use a custom packing mode that groups assets by path. It all works a treat, you load the base assets and unload them as needed, and the dependency bundles are loaded and unloaded as needed, provided nothing leaks a reference. When leaking a reference things start going wrong on reloading still, I am supposed to send my repro for to Unity but I have been too busy preparing for a release.

    This works much better than making everything addressable and using AssetReferences, because otherwise you have the same nightmare as putting everything in explicit bundles or resources, no real way to tracking whether your assets are used or not. If we delete one of the items from its group, all of its dependencies are stripped from our builds and there are no unused assets creeping in.

    All of the customisations to addressables required are actually quite trivial, although the custom packing does require modifying stuff that is not currently customisable without embedding the package into the packages folder.
     
  18. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    I already have a completely custom addressable bundle system that allows me to do this. I can isolate any dependencies I want with a few lines of code. However, since there are thousands of objects the number of extra isolation bundles also grows exponentially. Your solution only works to a point. At some point the isolation may as well be using the "pack separately" option on bundles. Which, by the way, fails hard due to path length limits unless you flatten a lot of your project.

    As an example of how my "bundle policies" work - the resulting bundles are already equivalent to your packing policy of "pack by path". They are explicit bundles but the results can effectively be the same.

    None of my bundle groups are defined by hand but instead by a complex system of policies. Some of the grouping have to do with where those assets live, and some of them have to do with their dependencies. It's entirely customizable. It still isn't enough to fix this problem. Right now I'm trying to track down where these specific instances of assets are causing the chain to go so deep but it's quite a mess to do so.
     
  19. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    959
    That depends on the structure of your assets. We don't have a rats nest because of what we are actually packing. As a result the number of isolation bundles grows less than linearly. We are currently at something like 5000 individually addressable assets (not-including the isolation groups) and they are packed in about 10000 bundles.

    That very much depends on what "by path" means. I extract particular sub-paths (specifically the last three fragments of the path) as the key and those also become the name of the asset bundle, solving both of those issues. None of the dependency bundles contain a single file, it's usually whole sets of textures and models. That also solves the path length issue on Windows.

    Yeah, we use a similar system running on Favo's Addressables Importer (I wrote the RegEx based rules and address replacement part of that). I'm interested about what rules you have based on your dependencies though, there are use cases I would have for that.

    Yeah, thankfully it has solved it for us. It took a 70 hour 5 day week and unholy amouns of debug logging peppered around much of Addressables and ResourceManager to figure out what was going on and another few days to rewrite the offending system, but everything is now loaded, unloaded, being collected and reloaded correctly. I really need to submit the repro for the underlying bug as it absolutely shouldn't be causing Unity to screw up reloading assets that are in bundles that are still loaded (according to the engine itself).
     
  20. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    @AlkisFortuneFish "packed in about 10000 bundles"

    This is what I'm trying to avoid. We are currently sitting around 300. With some slight changes I can push that to about 1000 (gathering shared dependencies just between particular sets of levels). There was even a time (maybe it has passed) where having that many bundles could completely break Android due to file handle counts.

    My suggested solution to Unity was to gather these interdependencies only at runtime but they chose the faster / easier route to fix the problem. I don't particularly blame them but the side effects are huge.
     
  21. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    959
    Ah, yes, this is an assumption on my side. In our case the 10k bundles are pretty intentional. They are individually downloaded as the player buys the item in-game. It downloads one or two bundles and the item is available. An item without any shared deps is one bundle, an item sharing some stuff is typically two, occassionally three, but then downloading another asset with those deps only downloads a single asset again.

    Edit: There are basically other things that are a lot more contained and monolithic in there, purchasable assets are where we want to have the granularity as close to 1-1 as possible.
     
    Last edited: Sep 3, 2020
    anycolourulike likes this.
  22. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    As to this part... it's a system that I used to use before addressables were a thing. It was easily converted to work with the new system and actually works quite well. I've updated it and added new features since. But the idea is that instead of just having regex filters as Favo seems to have (I'd never heard of it) you can write code that does whatever you want to gather assets. Some policies just search for particular asset types and put those in specific bundles. Some do the same thing but gather dependencies. I even recently wrote a completely data driven one that is using Odin Serializer to just choose the types to gather and declare what bundles they go in.

    I even wrote an xNode based policy that lets you set up complex bundle sets in a graph and declare what bundles are output. Every bundle output from policies have a list of assets to include, a bundle name, and a priority. With the priority in place it means multiple things might be trying to bundle the same asset but the one with the highest priority wins.

    In addition to this I have post process policies that run after everything is completed so that I can do a final pass on any bundles defined and either remove assets or gather further dependencies or whatever else I'd like to do.
     
  23. edem96

    edem96

    Joined:
    Jul 16, 2018
    Posts:
    5

    Can you demonstate your work?
    Thanks!
     
  24. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    I'm also stuck with a similar issue. As a simplified version I do:
    - Load a bunch of prefabs in Scene A via Addressables
    - Unload the reference in OnDestroy
    - Load a new scene
    - Repeat the steps to switch back and forth

    And for some reason, once I unload the prefab and reload, the new instance has invalid shaders/materials. The prefab is loaded correctly again, but the material or shader suddenly becomes pink or invisible.
     
  25. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    What version of the addressables are you using?
     
  26. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    1.18.4 and I've looked through this thread and tried some of the suggestions. In the meantime I suspect that something like this happens in my real project, but not in my smaller tests:

    - Load prefab via Addressables
    - Instantiate in the non-Addressable way
    - Unload the prefab Addressable reference when the scene closes
    - New scene loads, Unity calls UnloadUnusedAssets and destroys the material/shader because the prefab is unloaded, but my instance is not tracked by Addressables
    - New loads prefab and spawns new prefabs which work fine, because they also reload the shader
    - Some prefabs are leftover because they were moved in a different scene or DontDestroyOnLoad and weren't destroyed by the scene change. They now contain a reference to the previously unloaded item shader.

    So my current solution is, to simply not unload the prefabs if there are still instances alive, however I manage this myself, maybe it would be better to use Addressables.Instantiate.
     
  27. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    Ah, yes. That makes sense. Once you instantiate it, the addressables no longer know about any dependencies for it. Definitely try using Addressable.InstantiateAsync
     
  28. EdoC-QWERTY

    EdoC-QWERTY

    Joined:
    Feb 1, 2020
    Posts:
    75
    Hello I have an issue that might be related to this problem but I am not sure.

    I have 4 main scenes that are in the build and all the levels are addressables scenes.
    The scenes in build are:
    The "singletonscene" that contains all GameObject that I need all the time, this scene is never unloaded.
    The main menu, level selection and loading screen.

    In the addressables scenes there are prefabs that are not addressables.

    When I load an addressables scene async all the sounds are silent.
    The prefabs have a reference to the audiomixer that should be into the game files, right?
    It works almost like a ScriptableObject.

    Is this issue related to this problem? any suggestions on how can i fix it?

    I have a GameObject for the background music in the "singletonscene" and that works just fine.

    In the editor all seems to work fine but then when I test the build on phone there are no sounds.

    Thanks

    Edit: Solved by adding the AudioMixer to addressables
     
    Last edited: Sep 1, 2021