Search Unity

Bug When switching scenes, assets only used in previous scene are not unloaded.

Discussion in 'Editor & General Support' started by Zergling103, Jun 7, 2022.

  1. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    We're trying to deal with an issue that occurs where switching scenes causes assets that are used in the scene to accumulate indefinitely in RAM. There seems to be no upper limit on this and Unity will just allocate and allocate until you've exhausted your entire computer's RAM.

    So, if Scene A uses Mesh X, and Scene B does not, switching from Scene A to Scene B does not cause Mesh X to become unloaded. It remains in, and wastes, RAM.

    Things we've tried/considered to fix this problem:
    • Calling
      UnloadUnusedAssets
      , etc. after Scene A is unloaded.
      According to our findings, this does nothing; it will only have an effect on assets that are loaded via Resources, i.e. they're in a Resources folder.
    • Loading an intermediate empty scene between scene switches. When switching from Scene A to B, we instead switch to a blank intermediate scene and wait for Scene A to unload completely before proceeding to load Scene B. This similarly has no effect and fails to unload assets exclusively used in Scene A, even if we call UnloadUnusedAssets prior to loading Scene B.
    • Putting all of our assets into a Resources folder so UnloadUnusedAssets will do as advertised. If I'm not mistaken however, by doing this Unity will attempt to load all of the assets in our game initially. EDIT: Regardless, moving everything into a resources folder is a fairly ugly workaround to prevent memory leaks in my opinion.
    • Putting all of our scenes into a Resources folder. This could force
      UnloadUnusedAssets
      to work on things referenced by the level, without forcing all of the assets referenced by the level to be loaded. However, we'd need confirmation that this would work before committing to this fairly significant project structure change.
    • Overhauling our entire project to use Addressables or Asset Bundles. This... seems like a serious undertaking just to get textures and such to remove themselves from RAM when nothing is using them.
    • Assuming scene-based asset memory management would work as expected. It seems like a straightforward approach to managing memory - if an asset isn't being referenced in the currently loaded scene(s) - even indirectly - (and isn't in a Resources folder wherein it can be instantiated via script without a direct reference,) it won't be used, and therefore will be unloaded from memory - especially if we've explicitly asked for the memory to be unloaded via
      UnloadSceneAsync
      and
      UnloadUnusedAssets
      . I can't bring myself to buy the idea that the RAM hoarding until your computer runs out of memory and becomes unstable is intended functionality. I recall running into this exact same problem 10 years ago and - assuming we aren't at fault - it seems bizarre that this would still be an issue.
    • Something simple that we're doing wrong or forgetting. I have a hunch that there's probably something we're doing wrong, and that there's something we can do to get unused assets to clear themselves from RAM. Surely this is a simple problem to solve, given that Unity already has a very robust system in place for detecting when an asset is or isn't referenced by anything. Are we just not waiting long enough to attempt memory unloading after the scene changes? Do we need to enable some flag in the project settings?
    Anyway, thanks for reading my thread, and any help getting over this obstacle would be greatly appreciated. :)

    A confirmation of what the inteded procedure is in Unity to unload assets from memory after a scene switch would be extremely helpful - even if it'd be a massive undertaking to implement for some reason. As far as I know,
    UnloadUnusedAssets
    is the intended procedure for unloading after a scene change and should do exactly what I need. But for some reason it doesn't appear to work.

    Cheers
     
    Last edited: Jun 7, 2022
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,930
    To my knowledge, this won't load them into memory upon the program startup, but Unity will deserialise the look-up table for the Resources catalogue and this can take a lot of time depending on how much is shoved into your Resources folder(s).

    Have you looked at using the memory profiler to see what is being held in memory and what is referencing it?

    On top of that, are you creating any unmanaged assets? Such as
    new Texture2d();
    where you are responsible for destroying them afterwards?
     
  3. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    To my understanding, we are not creating assets like these at runtime. The vast majority of creeping memory usage appears to come from simple cases like a mesh, texture, terrain, etc. existing in the scene and not leaving RAM after a scene switch.
     
  4. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    To clarify, I'll outline my understanding of when Unity is NOT expected to unload assets on its own (that is, without explicit calls to force unloads):
    • When they are present and visible in a scene. E.g. a game object with a mesh renderer, mesh filter, texture and material. So long as this object exists in the scene, regardless of whether it is visible, active, enabled, etc., the mesh, texture and material it uses will not be unloaded.
    • If an asset, like a mesh, is referenced by a script on a game object in the scene, you can expect that mesh to always be in memory so long as that game object and script exists and continues to reference it.
    • If you reference a prefab on a game object in the scene, and those prefabs reference assets directly or indirectly, whether via script or otherwise, those assets will be in memory so long as that game object exists.
    • Any assets in a Resources folder - after being loaded - will not be unloaded on their own.
     
  5. ruzgames

    ruzgames

    Joined:
    Dec 23, 2019
    Posts:
    4
    Actually referenced or current scene objects have direct references so unity has to load them on scene loaded. Putting them on to resources folder wont make any changes with this process. So if you want to unload assets, you have to load them when it is necessary and unload when its done. I suggest you to use Adressables
     
  6. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,990
    Have you tried to replicate the issue in a separate project? Fromwhat you describe it would be as simple as loading a scene with a mesh, then change scenes, and check if the mesh remains in memory.

    I have a hunch that the last item on your list of things considered is the culprit. ;)
    Something as simple as some script that doesn‘t deallocate and through its references keeps a bunch of other things alive. I‘d start by looking at each and every singleton.
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,930
    Even something as simple as not unsubscribing to a delegate can cause memory to hang around.

    I'll repeat this I guess:
    I've not used it, but I understand that it can show you how a piece of memory is referenced.