Search Unity

Delete of GameObject causes extreme memory use

Discussion in 'Getting Started' started by JohnGaby, Sep 21, 2017.

  1. JohnGaby

    JohnGaby

    Joined:
    Jul 9, 2017
    Posts:
    7
    I am quite new to Unity. I have a small function which destroys all of the child objects of a GameObject.

    public void RemoveButtons()
    {
    while (transform.childCount > 0)
    {
    GameObject toRemove = transform.GetChild(0).gameObject;

    Destroy(toRemove);

    }
    }

    When this function runs, the unity editor hangs and memory is steadily allocated until all of the memory on my system is consumed and the computer crashes. Here is a graph of the memory usage as an example:


    The point at which the memory starts increasing is the point at which the RemoveButtons function was called. Memory returns to normal when I kill the Unity process. If I were to let it continue, the whole computer will crash.

    I am apparently doing something stupid here. Can someone explain the proper way to destroy game objects?

    Thanks.
     
    Enzzo likes this.
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    You're not doing anything stupid there. What platform is this?
     
  3. JohnGaby

    JohnGaby

    Joined:
    Jul 9, 2017
    Posts:
    7
    It is just running on Windows inside the Unity editor. I might point out that this RemoveButtons function is being called from a script which is attached to the objects being delete, in case that matters.
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I wouldn't expect that to matter, for a couple of reasons. First, Destroy doesn't actually destroy the C# object — it just tears down the underlying C++ data structures, after which your C# object reference will start throwing exceptions if you try to do anything further with it, and it reports 'true' if you compare it to null, etc. Second, even that doesn't happen right away unless you use DestroyImmediate; instead it just marks the object as condemned, and all that tear-down happens at the end of the frame.

    Ah, I bet I know what it is.

    You've written your loop under the assumption that when you call Destroy, that object is removed from the transform child list, and the next call to GetChild(0) will return a different one. That's probably not true. (I've never actually tried this so I can't say for sure, but it'd be consistent with my understanding for those things to stick around until the end of the frame.)

    So that means you've just made an infinite loop. (And one that apparently allocates data under the hood.) If you change your while loop to something like for (int i=transform.childCount-1; i>=0; i--) and destroy transform.getChild(i), it'll probably work fine.
     
    Kiwasi and Bill_Martini like this.
  5. JohnGaby

    JohnGaby

    Joined:
    Jul 9, 2017
    Posts:
    7
    I do believe you are correct. If I change the RemoveButtons by setting the parent of the 'toRemove' object to null before I destroy it, it works quite nicely.

    Thanks.
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Yes, that'd do it too, since transform changes do happen right away, and so that gets them out of your list. (Though it's not as efficient as the reverse for-loop.)
     
    Enzzo likes this.
  7. Enzzo

    Enzzo

    Joined:
    Sep 9, 2017
    Posts:
    8
    Code (csharp):
    1. public void RemoveButtons(){
    2.    if(transform.childCount > 0){
    3.        for(int i = transform.childCount-1; i>=0; i--){
    4.            GameObject toRemove = transform.GetChild(i).gameObject;
    5.            if(toRemove != null)Destroy(toRemove);
    6.        }
    7.    }
    8. }
     
    Last edited: Sep 27, 2017
  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Yes, that's essentially what I was suggesting (though note that neither of the if-statements above are actually needed).
     
    Kiwasi likes this.