Problem With Removing Objects On Current Scene

Problem With Removing Objects On Current Scene

Is there any suggestion ?

void OnDestroy ()
{
    Debug.Log("amount of gameobjects in scene before removing : " + gameObject.scene.GetRootGameObjects().Length); // shows 5 objects in scene 
    for (int i=0; i< gameObject.scene.GetRootGameObjects().Length; i++)
    {
        // Destroy(objects[i]);
        Destroy(gameObject.scene.GetRootGameObjects()[i]);
        gameObject.scene.GetRootGameObjects()[i] = null;
        Debug.Log(gameObject.scene.GetRootGameObjects()[i]); // after null assign still showing objects names ???
    }
    Debug.Log("amount of gameobjects in scene : " + gameObject.scene.GetRootGameObjects().Length); // still 5 ??? 
}

Thanks

You are getting a new array of root objects 4 times per loop, allocating a new array all 4 times.

Beyond the earlier point that you are manipulating the array/list while iterating over it this way, this isn’t just error prone but incredibly inefficient.

Call GetRootGameObjects() only once outside of the for loop and store the result. Then loop over that one, with a for or foreach.

Assigning null to elements in the array is unnecessary. Also Debug.Log can be pretty costly and is not stripped out in Release builds, so that might be impacting your performance as well. Plus, the object name you log out is of the next object as you just got a new list with the original object removed from it. This is also liable to give you an IndexOutOfBounds error when you remove the last element of the list.

void OnDestroy () // this is also called when the scene is unloaded, at which point it's pointless to destroy other elements in the scene as they are getting destroyed either way by the in process scene unload.
{
    Var objects = gameObject.scene.GetRootGameObjects();
    Debug.Log("amount of gameobjects in scene before removing : " + objects.Length); // shows 5 objects in scene 
    for(var I= 0; I < objects.Length; i++)
    {
        Destroy(objects[i]);
        Debug.Log(objects[i]); // now logs null, but really this line should be removed
    }
    Debug.Log("amount of gameobjects in scene : " + gameObject.scene.GetRootGameObjects().Length);  // if this still shows 5, give it a frame, though you'll need an external object to monitor and wait for a frame as this one is now destroyed.
}
  1. When destroying things, it’s good practice to work backwards through the array.

    Currently what could happen in this loop is:
    i=0, there are 5 objects, you destroy the first thing in the array.
    i=1, root objects array recalculates and now holds 4 things, you destroy the second thing in the array.
    i = 2, root objects now holds 3 things and we destroy the third.
    i = 3, root objects holds 2 things so we exit before looping again.

    The result is we do not destroy all the objects.

    If we loop from the # objects (-1) to 0 then we don’t have this same problem. You could also get the root game objects array before the loop and then keep using your local array instead of getting the array again each time.

  2. The call to get root game objects will return you your own local version of the root objects array, when you set it you’re not making any changes to the scene. The unity api provides this info on a readonly basis, we can make changes by creating or destroying gameobjects but can’t make changes to the underlying data

  3. If you’re doing this during edit mode then you’ll need DestroyImmediate instead, this is separate to the regular Destroy function as it does permanent damage to your persistent scene and should be used with caution.


If this doesn't help then please give more context about what's happening at this point. E.g. why you're trying to destroy other things during an OnDestroy, whether it's during edit mode or play mode, whether there are any console errors when this runs, whether this code destroys any gameobjects at all. I am a little suspicious of a child object trying to destroy its parent during the ondestroy call but lets see if any of the above points help first.

at first thank you very much for your detailed explanation …
In terms of better understanding , I am going to try to explain my aim with
whole OnDestroy code block …

void OnDestroy()
{
    if (uiTween != null)
        uiTween = null;
    DOTween.KillAll();
    if(game_ui_box!=null)
    {
        Destroy(game_ui_box);
        game_ui_box = null;
    }
    for(int i=0; i<gobjs.Count; i++)
    {
        Destroy(gobjs[i]);
        gobjs[i] = null;
    }
    gobjs.Clear();
    gobjs = null;
    strobjs.Clear();
    strobjs = null;
    sceneNameToLoaded = null;
    GameObject[] arr = gameObject.scene.GetRootGameObjects();
    for (int i=0; i< arr.Length; i++)
    {
           
        Destroy(arr[i]);
       arr[i] = null;
    }

    arr = null;
    Destroy(gameObject);
 }

this block is belong to mu GameUı script and it exists in every scenes of my game …
i made a simple profiler check to my game in unity and I realized there are so many
GC Allocating … so to prevent this I decided to write these removing codes to destroy function to decrease GC works … I am not sure if it is going to work or not , as a junior programmer :slight_smile:
in this block I put all string references in to strobjs list and remove them in destroy time , and I made the same thing to game objects with gobjs

actually , as you said I can play game both iOS and desktop but in iOS its a little bit low performance … in this graphic , I took the profiler screenshot while a ceil lamp making pendulum movement in my 2d game and in the same time I dragged my catapults string , in other words we can say that this is one of the max moments of the game in terms of performance …