Search Unity

Memory Management

Discussion in 'Editor & General Support' started by Wekthor, Apr 27, 2020.

  1. Wekthor

    Wekthor

    Joined:
    Apr 30, 2011
    Posts:
    164
    Hi,

    i am trying to optimize memory in my mobile game. I have few solutions i would like to try, but i am not sure what is the right one, since i am a bit confused about few basics things.

    1) Is it ok to just destroy Gameobjects to release them from memory? Something like each enemy and object checking for its distance to player and destroy its visual ( child gameobject containing mesh ) to release it from memory?

    2) Using LODs is nice for increasing fps, but it does not help with memory as all meshes stay in memory. Is it again just better to destroy meshes based on distance instead of using LODs if memory is main concern?

    3) Addressables. I have implemented small demo with addressables, but i am not sure what would be the purpose for memory optimization as destroying objects normal way releases the memory same way as when using Addressables. I understand addressables are good for live updates etc, i am just wondering about it only for memory optimization and if it has any benefits?

    I would be happy to hear any other recommendations.

    Edit:
    I created simple scene with textured Cube ( 3mbs ). Its an empty scene and with button i instatiate this box and with other button destroy it.
    Strangely when i profile this in build, there is no change in texture memory when the box gets created and no change is happening when i destroy it. Ie it looks like the texture is loaded in memory already and instantiating or destroying box does not affect memory. This is actualy quite confusing to me. I thought texture is not in memory unless the cube would be instantiated.

    Secondly even more strange. I have exact same scene in my test project for addressables. When i do the exact same thing there with same code and object, it works. When i instatiate the box, more memory is used, when i destroy it, it gets removed. Strangely tho, 3mb texture appears as 70mbs in profiler.
    This behaviour is exactly same on asset which is adressable and on other asset which is not addressable.

    Code (CSharp):
    1.  
    2. public GameObject asset;
    3. GameObject createdAsset;
    4.  
    5. public void LoadAsset()
    6. {
    7.         createdAsset = (GameObject)Instantiate(asset, Vector3.zero, Quaternion.identity);
    8. }
    9.  
    10. public void DestroyAsset()
    11. {
    12.        Destroy(createdAsset);
    13.   }
    14.  
    I know this should be basic stuff, but i am not able to get anything consistent. Based on what i read the memory should get released, but it does not. In other project same code works ( perhaps its because there is adressable package?) but 3mb texture takes 70mbs...
    I use profiler to keep track of memory on projects, but wanted to do more of a deep dive to realy know what exactly happens when, but i have hard time doing even basic stuff.
    If anyone knows about any good resource to understand memory management, mostly with game assets and not code, it would be of great help. Thanks.
     
    Last edited: Apr 27, 2020
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I don't believe you will see really any reduction in memory usage. Most likely you're using meshes which are shared between enemies and possibly a prefab, so destroying the visual of an enemy won't actually result in the meshes themselves being freed from memory.
     
  3. Wekthor

    Wekthor

    Joined:
    Apr 30, 2011
    Posts:
    164
    I want to use this for assets which are not in view based on the distance. things like one unique building which is in distance for example. Releasing memory for these assets would make it possible to have many unique assets. Right now i need to have everything in memory at one time, which is very limiting memory wise for bigger environment. I am trying to figure out what is the best approach to handle this.
     
  4. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,452
    Loading stuff from disk into memory takes time. You can't just upload the texture of an enemy behind you into RAM and then VRAM just as you turn around to face it. You'd get a bad frame drop for that.

    If you're not using Addressables, on build Unity bakes a reference tree for all assets that are referenced in a scene via GUID (like drag and drop assignment to some fields in the editor) and will load all of them when you load that scene. If you destroy a RenderTexture or a GameObject ad-hoc, that memory can get freed, but any assets (Mesh, Texture, sound...) It used are still loaded in via the scene, in case you want to instantiate a new one.

    • are you Profiling the Editor or a build player. Editor memory usage can be quite different.
    • what platform are you testing on?
    • Where do you get the 3mb size from
    • What compression settings are set?
    • What memory Profiler are you using to check this? The Memory Profiler Module? Simple or detailed? The Memory Profiler package?
    Now to your other points:
    It sure is ok, but as mentioned won't free the memory of the assets. That is tied to the scene and will only be unloaded if the scene is unloaded. And even then, it won't just unload if you load any new scene, because some memory might be shared by that scene so unity will actually only Trigger Resources.UnloadUnusedAssets on these assets for the next scene load after the one that flushed the original scene out. Or you could call that manually

    That's the balance you need to strike for LODs and Mip Maps, higher memory usage, lower frame times.
    Once again, loading this stuff from Disk->RAM->VRAM is to slow to just do that ad-hoc as that enemy approaches the player.


    I haven't used Addressables yet, so I can't comment on that. And in any case, use the Profiler to validate any assumptions.
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Is there any good way to debug that tree?

    It's easy enough to figure out what assets goes into the build (by parsing the build log), but what I'd really love is to see why assets are in the build. There's quite a few instances of "why is our build so large? Oh, all these psd files are there. But we're not using those! Why are they included?", which tend to be hard to debug.

    If we could just get hold of that tree, we could use it to build a database of "which things require which", which would help us prune the tree. That'd be very valuable.
     
  6. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,452
    Well, there's the Memory Profiler references of loaded assets once the scene is loaded
    Or just make a build with that one scene and check the build report / build report inspector.

    I guess that's not quite what you wanted though. So I guess, no?

    Also, I think that reference tree might be a bit more transient than how I made it sound. I'm not too firm with that system.
     
  7. Wekthor

    Wekthor

    Joined:
    Apr 30, 2011
    Posts:
    164
    @MartinTilo

    Thanks a lot for the explanation. It makes much more sense now.
    So my question now would be, is there some other solution how to unload/load assets into memory? Say i am building for older mobile device, which has for example 800mb ram, if i use more memory, game starts crashing. So the way i understand it, is that i need to have all my assets for that scene loaded all the time, making those 800mb hard limit on amount of assets i can have in the scene.

    But lets say i have several environments in the scene, like desert and forest. When player is in desert, i dont need trees in memory, so it would be great to unload them and load them only when player enters forest. This way i could make sure that in any area assets are never more than 800mbs, but the scene has in total for example 2000mbs of assets, which it loads/unloads based on where player is in the scene.

    Is there some solution for this?
     
  8. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,452
    I guess you could split these into multiple scenes, e.g. one scene per environment and load/unload (additive and async) them as you need them, or possibly use Addressables. Also remember to call Resources.UnloadUnusedAssets once a scene is unloaded.