Search Unity

Objects not unloaded from memory when loading a new scene

Discussion in 'Editor & General Support' started by gecko, Dec 20, 2020.

  1. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,241
    We recently discovered that many objects (meshes and textures) are not being unloaded when we load a new scene. I thought that this bug report was of the same issue:
    https://issuetracker.unity3d.com/is...90.900831227.1607437678-1498537908.1592688051

    But have just upgraded our project to 2019.4.16 and it's still happening. I loaded a saved game in Scene A, then did an in-game trigger to go to Scene B (SceneManager.LoadScene(sceneName, LoadSceneMode.Single);), and after that's finished loading, did a Memory Profiler snapshot and there I can see many textures and meshes from Scene A still in memory, although they are not present in Scene B. If I load a save that goes directly to Scene B, then those objects are not in memory, and RAM usage is substantially lower.

    This obviously has a huge effect on RAM usage, and has been causing some crashes for beta testers. We are releasing an update soon and really need to get this fixed.
     
    Last edited: Dec 20, 2020
  2. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    This is intended behavior. Unity by default assumes that you'll be using most resources across scenes and unloading and reloading them would be too much of a burden on the load times. Also it doesn't definitely know ahead of time which ones won't be used anymore after loading and after loading its already kind of too late for the high water mark and the pools would already have been resized to fit the additive memory requirements, and unloading the resources now would once again only take too long and only yield gains if the memory usage is set to grow much while in this new scene. Before loading out the last scene, Resources.UnloadUnusedAssets will be triggered, clearing up memory from a previous scene though, to make some room for the next scene.

    So besides the usage of Addressables or taking slightly longer level load times by loading an empty scene in between, one way to facilitate better memory management without too much additional load times would be to have a base scene which uses any shared resources. This could also be a menu scene and if it isn't taking to much time to load, the inital scene to load or the second one after a mostly empty one that predominantly is there to start a loading bar UI or similar. This shared resources scene can then be loaded into in-between scene changes. This will add somewhat o the loading times but allow a lower high water mark on memory usage.

    Edit: fixed some autocorrect issues for readability
     
    Last edited: Jun 28, 2023
  3. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,241
    Thank you very much for the detailed answer! Wow, I had no idea that's how Unity worked....but I haven't had memory issues before that prompted deeper analysis.

    So loading an empty intermediary scene will make the overall process take longer because unloading objects takes time...but we can't unload specified objects in Scene A before leaving it, right? (Or could we fade to black, unload them, and then go to Scene B?)
     
  4. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    Yes it would make it take longer. You can call Destroy on specific Asset type objects, e.g. Textures or Materials that you might have created from code (instead of loaded from disk as a deepmdency via an inspector assigned reference), to unload those. Assets loaded as dependencies can not be unloaded in a targeted way, only through Resources.UnloadUnusedAssets (aka AssetGC) That will unload those which aren't used anymore, but is slow and also already running as part of a destructive scene load/unload, so you'd run it twice. While it runs as part of the scene unload, it does so before the Scene is unloaded, so if you have some bigger Assets that are only used in a few controlled places in the Scene, you could call Destroy on the Scene Objects (GameObjects and their Components) before leaving the scene, which should ensure that the automatically triggered AssetGC would unload these with the scene. But Profile that and make sure the clean up with Destroy A) removes all reference so that it actually helps and B) isn't slower than just loading a scene in between.

    And yes you would need an empty scene in between scene A and B to load to and you could fade via scene independent ui or screenspace shaders to mask this.

    Edit: updated with a bit more details of what couldbe done but is likely a bit too involved for general recommedation. If fine grained Asset loading and unloading is needed, using Addressables is the recommended way as it allows for a more targeted, better instrumented and more automatic solution for memory management.
     
    Last edited: Jun 28, 2023
    gecko likes this.
  5. Interwinner

    Interwinner

    Joined:
    Jan 4, 2023
    Posts:
    3
    Hello
    I am very upsetting due to increasing memory even empty scene that is independent from other scene.
    ** There are some DLLs in my project.
     
  6. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    Hello @Interwinner ,
    That sounds like an unrelated issue. I'd recommend using the Memory Profiler package to analyze that, but do note that it does not cover memory allocated in native plugins/DLLs unless these use the Memory Manager API for low-level native plug-ins to allocate their memory. If capturing 2022.2+ Editors or Players auch memory is however fully captured as "Untracked" on all platforms, along with some other bits (check the package's manual for details on what Untracked can contain). Untracked captured from older versions can also contain plug-in allocated memory but Untracked memory stats are not tracked on all platforms and not with too much certainty of that amount being correct.

    When you see only or predominantly the Untracked amount grow between captures, (take two snapshots while memory usage grows, and if capturing the Editor, do not open them until the second one is taken to avoid muddying the waters) then the DLLs are likely at fault. Try removing them in a Divide and Conquer manner to see if that fixes it and to bisect which one is the one at fault.

    And if you need more input on that's please open a new thread. You can ping me, or apply the profiling tag, or post into the Profiler Previews subforum it it is predominantly about the Memory Profiler as a tool.