Frank Vieira
Frank Vieira

Reputation: 13

Why is this code causing memory leaks?

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);
        }
    }
}

Upvotes: 1

Views: 1609

Answers (3)

Programmer
Programmer

Reputation: 125255

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.

Upvotes: 1

Scornwell
Scornwell

Reputation: 605

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

Upvotes: 0

PhillipH
PhillipH

Reputation: 6222

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.

Upvotes: 0

Related Questions