1

There is only a default camera and a single GameObject.

Why destroyed game objects are still in-memory ? I've tried to call the GC manually, Resources.UnloadUnusedAssets and a bunch other hacks without success. My game needs to create GameObjects on the fly... ObjectPooling of course could be done but since the player will be playing for hours and there are tons of different sprites I think this would still be a problem.

public class Game : MonoBehaviour
{

    private List<GameObject> objects;

    // Use this for initialization
    void Start()
    {
        this.objects = new List<GameObject>();
    }

    // Update is called once per frame
    void Update()
    {
        foreach (var item in this.objects)
        {
            Destroy(item);
        }
        this.objects = new List<GameObject>();
        for (var i = 0; i <= 1000; i++)
        {
            GameObject gb = new GameObject();
            gb.name = i.ToString();
            SpriteRenderer renderer = gb.AddComponent<SpriteRenderer>();
            renderer.sprite = Resources.Load("Sprites/grass", typeof(Sprite)) as Sprite;
            gb.transform.position = new Vector3(i, transform.position.y, transform.position.z);
            this.objects.Add(gb);
        }
    }
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • you're creating and destroying way too many objects every frame, no game would ever need that – Daahrien Jun 22 '17 at 17:03
  • @Lestat My game itself does not create that many objects every frame.... This code was crafted carefully to reproduce the problem in an easy manner... I would appreciate if someone answer why memory never gets released (and keep growing forever) in such a simple code... Thanks. – Frank Vieira Jun 22 '17 at 17:28
  • Hi, the problem is `gb.AddComponent()` as mentioned in my answer. You can comment that line of code to verify that statement. You need Object pooling two examples are linked in my answer. – Programmer Jun 22 '17 at 20:35

3 Answers3

1

There are three problems in your code:

1.The problem is gb.AddComponent<SpriteRenderer>();. Adding SpriteRenderer does not seem free the memory until scene reloads. This is the main problem in your code.

2.Remove the this.objects = new List<GameObject>(); from the Update function. You have already done this in the Start function. You will only create more Lists that's not needed.

That line of code should be replaced with this.objects.Clear(); as that will clear the List before adding more Objects to it on the next line.

3.You should never call Resources.Load in the Update due to performance problems. This is like loading a file every frame and that will affect the performance of the game.


ObjectPooling of course could be done but since the player will be playing for hours and there are tons of different sprites I think this would still be a problem.

No and no. Object pooling is the solution to this so that you will not be adding new SpriteRenderer each frame.

Read this for an explanation and this for the ArrayObjectPooling class that can easily be used for Object pooling.

Programmer
  • 121,791
  • 22
  • 236
  • 328
0

Is your GameObject a COM object ? If so then you increment the reference pointer by adding it to the list, but dont release the reference counter by disposing the gb variable.

PhillipH
  • 6,182
  • 1
  • 15
  • 25
  • I'm not sure about what is a COM object (I'm a C# beginner) but by looking at Unity documentation is seems not the case. Thanks. – Frank Vieira Jun 22 '17 at 17:29
0

The reason you have a memory leak and calling your garbage collector is not doing anything is because of how you are declaring

private List<GameObject> objects;

You declared this as a global variable when instantiating your public class Game:MonoBehavior.

As the garbage collection is called this will eventually put the List into a generation 2 pool of objects that will not get disposed of until the class is no longer used.

I see two options really, you can make the scope of the object smaller by placing it within a method allowing the memory to be released by the normal garbage collector since it will become a generation 1 or 0 object at that point.

or you can call TrimExcess() on your List which will reduce the memory of any allocated space of the list down to the amount of memory actual held by the objects in that list.

Here are some helpful links about the garbage collector and object generations for C#:

https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals

http://www.dotnettricks.com/learn/netframework/net-garbage-collection-in-depth

Scornwell
  • 597
  • 4
  • 19