1
\$\begingroup\$

Manager script(simple script attached to an empty GameObject on scene) on Start() instantiates 1000 default cubes with rigidbody component added and gravity check ticked.

public class SpawnScript: MonoBehaviour {

    public bool MakeInstances = false;
    public bool GC = false;
    public GameObject instance;
    public int numberOfInstances = 1;

    void Start() {
        if (MakeInstances)
            for (int i = 0; i < numberOfInstances; i++)
            {
                Instantiate<GameObject>(instance);
                //GameObject tempInstance = Instantiate<GameObject>(instance);
                //GameObject.Destroy(tempInstance);
                //tempInstance = null;
                //Debug.Log("obj is " + tempInstance);
            }
    }

    private void Update()
    {
        if (GC)
        {
            GC = false;
            System.GC.Collect();
            Resources.UnloadUnusedAssets();
        }
    }

Cube prefab have self destruction script like this

public class SelfDestruct : MonoBehaviour {
    public float seconds;

    IEnumerator DestructIn(float time)
    {
        yield return new WaitForSeconds(time);
        Destroy(gameObject);
    }

    void Start () {
        StartCoroutine(DestructIn(seconds));
    }
}

Profiler "simple" shows memory usage around 0.7gb after instantiating is done. I expect it to get freed after destroy, but it does not. Tried to apply GC and UnloadUnusedAssets, did not help. Tried to destroy them all right after instantiating, still no luck.
Is it a bug or am I doing something wrong? This is definitely not a real world example, just wanted to study memory management in Unity and got stuck here.

P.S.A few more strange points I have noticied with profiler:

  1. In Editor/"Detailed" mode it would not notice that I have 1000 cubes on a scene, while in Build/"Detailed" it did
  2. In "detailed"(both editor and build) data usage is around 200mb which is definitely not true(broken?), because Windows Task Manager shows me that build is using around 0.9gb. Bigger than what "simple" tells me, guess some overhead is present

EDIT:
Thanks to @Candid Moon for performing a test, he did confirm that software won't eat all the memory. Guess I should add screenshots with my observations Here we have no instantiation, simple clean scene with a plane, eats around 100mb No instances Now let us go wild and make that instantiation on a startup

enter image description here Alright, we did instantiate a lot of objects, they collided and flew away in outer space, in 5 seconds they were destroyed. We are back to clean scene with plane, just like the one with 100mb. Except for now it eats up 0.75gb. Left it hanging for half an hour to see if memory gets freed, nothing happened.
Is it a usual behavior? Is there any way to free all the used memory and go back to 100mb? Can/Should programmer do anything on his side to deal with such situations?

\$\endgroup\$
  • \$\begingroup\$ Why are you collecting before unloading? Where do you set the GC to true? \$\endgroup\$ – Sidar Mar 1 '18 at 6:57
  • \$\begingroup\$ @Sidar As far as I'm aware this is Mono's GC and it does not handle Unity's GameObjects. Anyway, tried before and after, results are same. GC is public bool as you can see, just a tick in editor to run and see if values in profiler get changed. \$\endgroup\$ – metamorphling Mar 1 '18 at 7:05
2
\$\begingroup\$

1000 isn't enough. I have taken your scripts and modified them a bit and it's showing that everything is working correctly. Instantiating 1000 objects gives you less than 1 mb - if you have seen any change it was impossible to spot it because of many factors like unity editor own objects and garbage creation. Calling GC doesn't necessary start the process (as far as I know - but I'm not sure about this one).

1 2 3

Here you can see how the memory is freed. Also, if it didn't free the memory I wouldn't have a constant memory usage when instantiating and deleting 100 cubes every frame. It would just gradually increase until I run out of memory. On these pictures I'm trying to show that the memory increases because we create many instances at once.

4 5 6

Memory went back to normal. If you create them at the same position the physics engine creates a lot of garbage because of collisions, so I modified creation on random positions.

Here you go:

public class SelfDestruct : MonoBehaviour 
{
    public float seconds = 5f;
    public double[] garbage = new double[12500]; //!!!!!!!!!!!!!!!!!! BE CAREFUL - IF your computer is slow and you attach this script the array will be so big to display that UNITY MAY LAG. TRY TO DECREASE THIS IF you experience freeze

    IEnumerator DestructIn(float time)
    {
        yield return new WaitForSeconds(time);
        Destroy(gameObject);
    }

    void Start()
    {
        StartCoroutine(DestructIn(seconds));
    }
}

public class SpawnScript : MonoBehaviour 
{
    public bool MakeInstances = false;
    public bool GC = false;
    public GameObject instance;
    public int numberOfInstances = 1;

    private void Update()
    {
        if (GC)
        {
            GC = false;
            System.GC.Collect();
            Resources.UnloadUnusedAssets();
        }

        if (MakeInstances)
        {
            for (int i = 0; i < numberOfInstances; i++)
            {
                Instantiate(instance, Random.insideUnitSphere * 300f, Quaternion.identity);
                //GameObject tempInstance = Instantiate<GameObject>(instance);
                //GameObject.Destroy(tempInstance);
                //tempInstance = null;
                //Debug.Log("obj is " + tempInstance);
            }
        }
    }
}

I didn't call CG even once during testing. Only in the end to try if anything changes - result is nothing has been changed.

Conclusion: Destroy works as intended and it frees up the memory. Other problems might be in physics or something else. Coroutines were used as well, so they don't seem not to free up the memory usage.

EDIT

Now if we look at profiler. 7


8

We can see that profiling data stacks memory. And if you try to profile yourself you will be able to see how many objects in scene you have right now and if they are being destroyed and if the memory is freed.

\$\endgroup\$
  • \$\begingroup\$ Guess some GC mechanism for system to not go OOM is present. And yet I'm still left wondering as to what can be done with "physics engine creates a lot of garbage because of collisions"? I will edit question and add my observations on this matter \$\endgroup\$ – metamorphling Mar 2 '18 at 7:11
  • \$\begingroup\$ @metamorphling consider creating a new question for that. As this one should stay related to Destoy and not confuse people who search for answer. Also, I just got a glimpse of that garbage creation and didn't pay much attention to it, so you could try making some kind of benchmarking for physics. I think it is expected behaviour. \$\endgroup\$ – Candid Moon _Max_ Mar 2 '18 at 18:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.