Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Why is destroy and then null not giving the memory back?

Discussion in 'Scripting' started by ratamorph, Aug 14, 2009.

  1. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    I'm doing some simple tests on instantiation and destruction and it seems to me that when I instantiate Unity allocates new memory (obviously), but when I call destroy on those created objects it removes them from the scene but the memory is never freed...

    This has me puzzled, is there something I'm not quite understanding here? can someone explain how I'm supposed to get the memory I used back?

    I can't always wait for the garbage collector to free up my memory, what If I want to instantiate a bunch of objects and delete older ones so I don't run out of memory?

    here's the code I'm using to test

    Code (csharp):
    1.  
    2. var numInstances : int;
    3. var prefab : GameObject;
    4.  
    5. private var instanceCount : int;
    6. private var instances : GameObject[];
    7.  
    8. function OnGUI()
    9. {
    10.     if(instanceCount == numInstances)
    11.         GUI.enabled = false;
    12.     else
    13.         GUI.enabled = true;
    14.    
    15.     if(GUI.Button(Rect(0, 30, 100, 30), "Instanciate"))
    16.     {
    17.         instances = new GameObject[numInstances];
    18.        
    19.         for(var i : int; i < numInstances; i++)
    20.         {
    21.             instances[i] = Instantiate(prefab);
    22.             instances[i].transform.parent = transform;
    23.             instanceCount = i + 1;
    24.         }
    25.     }
    26.    
    27.     if(instanceCount == 0)
    28.         GUI.enabled = false;
    29.     else
    30.         GUI.enabled = true;
    31.  
    32.    
    33.     if(GUI.Button(Rect(0, 60, 100, 30), "Delete"))
    34.     {
    35.         for(var j : int; j < instances.length; j++)
    36.         {
    37.             Destroy(instances[j]);
    38.             instances[j] = null;
    39.         }
    40.        
    41.         instances = null;
    42.         instanceCount = 0;
    43.        
    44.     }      
    45. }
     
    rainbowmimizu likes this.
  2. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    I read a lot of the other posts about memory issues, most of the being for iphone projects, I'm not working on iphone at the moment, just a macOS standalone.

    I'm still a little confused as in how to force the GC to release the memory, do I need to destroy every single component in my prefab instance before I destroy the instance?, do I also need to manually destroy the hierarchy that my instance might have? Do I set to null after in this cases?

    I need to figure out how to release all the memory allocated for a parent's children, so I can clean up the memory used by a bunch of prefab instances after I combine the meshes for performance.
     
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The garbage collector is part of Mono and only works on Mono objects anyway, not Unity assets like GameObjects.

    --Eric
     
  4. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    mmmm so, what am I doing wrong? do you know?
     
  5. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    Really? Is this true? So you're saying the memory for any GameObject is never freed, when the GO is destroyed?

    Ratamorph - you could try calling the garbage collection direct, using:
    Code (csharp):
    1. GC.Collect()
    let us know if that makes any difference.

    - Ben
     
  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Wouldn't have said it otherwise. ;) Mono knows nothing of Unity assets; .net wasn't written with Unity in mind. GC.Collect() only cleans up unused Mono objects and won't have any effect on Unity assets.

    Unity iPhone has Application.GarbageCollectUnusedAssets(), which applies to Unity assets. Currently this is either undocumented or not present in regular Unity. At least on scene load these should be cleaned up; not clear on exactly what happens otherwise. Certainly I have games which have many objects constantly instantiated and destroyed, which don't seem to ever run out of memory.

    --Eric
     
  7. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Destroy has no immediate handling, I actually don't even know by which logic these objects are destroyed, if it depends on the creation of new objects or whatever.

    If you want to clean the stuff directly, use DestroyImmediate instead of Destroy
     
    sean244 likes this.
  8. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    I know GC doesn't happen immediately, but it sounds very much as though you're saying that it never happens for unity objects. I had to test this, because it would seem as though things were terribly broken if things weren't garbage-collected in Unity.

    (tests...)

    Ok - Unity instances (such as GameObjects) are, in fact, garbage collected. I tested this by creating a standalone build where 1000 new gameobjects are created per frame, then destroyed. The memory usage of this standalone build remains constant, fluctuating up and down slightly which indicates that the GC is quite happily doing its job of freeing up the memory used by these destroyed instances.

    I can only assume that there is some kind of misunderstanding between your comment about 'assets' and the original poster's question about instances.

    Ratamorph - I guess this doesn't bring us any closer to understanding what's causing your problems, but it is definitely the case (as far as I can tell) that garbage collection works as your would expect for destroyed unity gameobjects.

    - Ben
     
    sean244 and ecv80 like this.
  9. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    I did some more tests, and seems like unity uses up as much memory as it has to as the GameObjects get instantiated, when I call Destroy it doesn't free up that memory to the OS, instead it seems like it marks it as available and when I instantiate again, it just uses up that marked memory so there is no actual memory leak.

    The problem with this is that in my project i create a lot of objects and by a lot I mean 30k+ prefabs, which uses up a quite a bit of memory, then I combine the meshes of all these prefabs into one using a custom made meshCombine script that will combine when I call a function instead of on Start, this also allocated memory for the combined mesh, but I end up with a bunch of memory allocated for the process of creating this combined mesh.

    I tried DestroyImmediate instead of Destroy and the result is the same.

    I haven't noticed any decrease on memory usage after this, so it seems like unity keeps increasing the heap as it needs but only releases that memory when loading new scenes or quiting the application, is that so?
     
  10. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    220
    It would be great to hear competent opinion of Unity engineers on subject, cause this topic is very important. Right now i'm in the middle of panic, because my application after some switching between scenes eats up 1,5Gb of memory and dies horribly, and it's not the behaviour i expected from Unity memory management.
     
  11. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    Note that using 'Destroy' is very important. If you create a GameObject, Texture2D, or anything else that inherits from the UnityEngine object class, you must use Destroy to get rid of it. They won't be GC'd if you just get rid of all references to them without calling Destroy on the object.

    For example if you create a new Texture2D whose only reference is a locally scoped variable, and then let that variable fall out of scope without calling Destroy on the texture object, you will have a memory leak - since you will no longer have a reference with which to destroy it.

    So - provided you're making correct use of Destroy, GC should do the right thing (unless there's some hideous bug that I'm overlooking!).

    - Ben
     
    ecv80 likes this.
  12. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    The question then becomes, Is the correct behavior the one I'm describing or I'm I doing something wrong?
     
  13. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    220
    I suppose this meant for objects, created from code. What about objects, just built into scene itself? Should i destroy them all manually before calling Application.loadLevel()?


     
  14. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The Mono garbage collector does not garbage collect Unity objects, which has been stated by the developers on the forums several times. Calling GC.Collect() never touches Unity objects, period. Obviously Unity has its own memory handling for these, or else, indeed, Unity would be pretty broken. But you can't do it manually, since Application.GarbageCollectUnusedAssets() (which is not the Mono garbage collector) is not available in regular Unity at this time, only Unity iPhone. Probably because the iPhone has a much much smaller amount of memory available compared to a desktop, so it's more likely you'd need to use it.

    Loading a new level automatically destroys everything in the current scene.

    --Eric
     
  15. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Rather, GameObjects are stored in a heap collection which only grows and when something is destroyed from the heap, that heap remains the same size and has room for more object, for them to clean that up they have to always make a copy of the collection by used elements and destroy the previous heap, which then takes up twice the memory for just that single process alone.

    This is convenient for the programs, as Eric pointed out he creates and destroys tons of GameObjects, his memory will only grow as long as it takes to make the largest heap to store his data, when he destroys items, the heap has room again, when you load a new level, the heap should be destroyed unless you carry over any GameObjects in which case all they do if you use DoNotDestroyOnLoad is that they cary the heap to the new level and re-use the current heap.

    It is pointless to destroy the heap and create a new one during a given level anyway.

     
  16. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    220
    Thanks, zumwalt, now it makes some sense.
    One question remains although. How to make heap destroyed in the end of level to free memory, and in the same time keep some vital information between levels(game info - variables, score, managers e.t.c.)


     
  17. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    Thanks for the replies and the interest in this topic by so many, now I finally have a clear understanding on what is happening with the memory unity is allocating for it's purposes.

    I guess the root of my problem is instantiating 30k prefabs... I made a script that just directly adds the vertices to a collection and then creates the mesh on demand, that way I don't instantiate the prefabs and the heap doesn't grow as much.

    Is there anything that I need to take into close consideration when dealing with GameObjects as far a memory? or is it pretty much fool's proof?
     
  18. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    220
    It was a silly question, answer is - use static properties instead.
    But there is another question.
    How to build big project?

    I managed to solve memory problems in the game when it's running, by using manual destructors and don't using DoNotDestroyOnLoad. But these things doesn't help in the building process. When i add all scenes, and press "Build" button, Unity first copress all textures, next opens all scenes one by one. With every opened scene memory usage is growing, on the 4th scene it was 1,5gb. Then it just shows "Out of memory" window and cease to work further.
    For this project we solved this by decreasing texture sizes, so build was finised before all available memory was taken. But what if i have 5 scenes, or 10? How theoretically i can build big project, if 4 gb of installed memory is not enough?





     
  19. Yorick2

    Yorick2

    Joined:
    Jan 24, 2009
    Posts:
    297
    I've had the same problem with a project that didn't publish because of memory on windows.

    Luckily we have a mac in the office which doesn't have the same problem.
     
  20. QFS

    QFS

    Joined:
    Jan 22, 2009
    Posts:
    302
    I havent tried building multiple scenes yet (I'll have to try it now), but what you experienced worries me.

    If it wont build a large project then I wont be able to use Unity .... hopefully that wont be the case.
     
    Smithy43 likes this.
  21. ratamorph

    ratamorph

    Joined:
    Sep 2, 2007
    Posts:
    458
    I fixed some of the memory issues I had with instantiating a lot prefabs, but now I have problems with the memory Arrays use. Here's the code I'm using to test this particular issue:

    Code (csharp):
    1.  
    2. var elementsToAllocate : int = 10000;
    3. var dimensions : int = 1000;
    4.  
    5. private var done : boolean = false;
    6. private var testArray : Array;
    7.  
    8. function Start()
    9. {
    10.     testArray = new Array();
    11.    
    12.     for(var d : int = 0; d < dimensions; d++)
    13.     {
    14.         for(var i : int = 0; i < elementsToAllocate; i++)
    15.         {
    16.             testArray.Push(Vector3(GetRandomFloat(), GetRandomFloat(), GetRandomFloat() ) );
    17.         }
    18.     }
    19.    
    20.     done = true;
    21. }
    22.  
    23. function GetRandomFloat() : float
    24. {
    25.     return Random.Range(Mathf.NegativeInfinity, Mathf.Infinity);   
    26. }
    27.  
    28. function OnGUI()
    29. {
    30.     if(!done)
    31.         return;
    32.            
    33.     GUI.Label(Rect(0,0,100,30), "Done");
    34.    
    35.     if(GUI.Button(Rect(100,0,100,30), "Clear Memory"))
    36.     {
    37.         testArray.Clear();
    38.         testArray = null;
    39.        
    40.         System.GC.Collect();
    41.     }
    42. }
    43.  
    44. function OnApplicationQuit()
    45. {
    46.     if(testArray)
    47.     {
    48.         testArray.Clear();
    49.         testArray = null;
    50.     }
    51.    
    52.     System.GC.Collect();
    53. }
    The memory will not be released when I press the clear button, even when doing GC.Collect(), what's even worst if that if you run this in the editor it will allocate more memory each time you press the play button so the Unity editor will keep eating up memory.

    The project I'm working on needs to parse a large file, I store the temp data in Arrays, How do I release the memory the parser used up so I have actual memory for the application? Is Array a unity object? if so should I use ArrayList instead?

    EDIT:
    I created another topic since this has nothing to do with the destruction of GameObjects anymore.

    here's the link


    http://forum.unity3d.com/viewtopic.php?p=192083#192083
     
  22. Xaurrien

    Xaurrien

    Joined:
    Jul 2, 2012
    Posts:
    20
    I had the same issue loading/unloading assetbundles in the same scene => I found the solutin here http://answers.unity3d.com/questions...up-memory.html
    So after destroying your gameobjects, if the memory doesn't get free try this :

    Code (csharp):
    1. Resources.UnloadUnusedAssets();
    and voilà !
     
  23. ciprian_facerig

    ciprian_facerig

    Joined:
    Mar 25, 2015
    Posts:
    34
    Resources.UnloadUnusedAssets(); has resolved the issue of ever increasing memory for us too :)
     
    DerLasseHenrich likes this.
  24. Develax

    Develax

    Joined:
    Nov 14, 2017
    Posts:
    67
    Resources.UnloadUnusedAssets()
    worked for me too.
    Reading this branch is like reading a detective story with a good resolution at the end :)
    It's quite strange that Unity experts couldn't help with it.
     
    Last edited: Mar 6, 2020
  25. yuplis

    yuplis

    Joined:
    Apr 2, 2016
    Posts:
    2
    Resources.UnloadUnusedAssets(); Worked for me 2, aparently the DontDestroy dosent destroy even if you destroy it, you need to use this in order to really get rid of the Gameobject or asset