Texture leaks when loading scenes additively

We are encountering an issue with textures leaking, and i am not sure this is a bug, or some form or expected behaviour by the engine:

What we do is create textures (and sprites) at runtime from .bytes files (TextAsset), and then load these into a SpriteRenderer.

This is done in a scene that is loaded additively (on top of the current scene). Once we’re done with it, we destroy its root object and all objects in that scene are destroyed.

The problem is that the textures that were dynamically created for that scene are left in memory and are not freed up automatically.

So, my questions are:

  1. What is the default Unity behaviour with Texture2D objects ? are these cached automatically somehow at the native level ?

  2. When destroying a SpriteRenderer component - should the underlying Sprite (and its texture) be disposed and destroyed as well ? if not, the memory is still in use even after the object was destroyed (leak).

I met this behaviour before.

I think you need to manually call Destroy() on each texture allocated at runtime or call Resources.UnloadUnusedAssets() which should do it automatically

4 Likes

Thanks @mholub that is what we’re doing now.

I am not sure this is a bug or not though… I would assume the engine should clean up its resources.

In most cases unity does a good job about this, however in my fair share of browsing for “the best” game engine, most API’s and engines have the same issue in terms of Texture memory leaking. I’m not sure the reason behind it, guess I got some reading to do!

EDIT: According to this, texture data is held on the GPU, instead of RAM. Not sure if it applies to unity, but its a side conversation topic for sure

Like mholub said, assets like textures, meshes and materials that are created by you in runtime will also need to be destroyed by you when you don’t need them anymore.
I’m curious though as to why you would store textures as TextAssets.

@ThermalFusion this is an optimization technique. It makes the built game package smaller, at the expense of doing some more work at runtime.

Another thing i have noticed is that textures that are not created at runtime (e.g: drag a sprite i to a Sprite Renderer) are also not freed automatically, only when explicitly destroyed or a new scene is opened.

Not sure why it is like that or if it is better than unloading and loading a texture on every usage.

@Lorinthio . I am not sure how Unity is storing its textures internally… In the profiler i can see the textures + memory usage, not sure if that is GPU memory or not.

In anycase it would be great to receive an “official” reply for this issue.

I don’t think you want Unity clearing out these textures automatically for a few reasons:

Loading the texture from disk to RAM is slow, so you want to avoid this operation if possible.
Textures loaded from disk may be applied immediately, or maybe loaded preemptively.
Textures that are used on objects that are destroyed might be needed again, possibly very soon.

I would call the loading and unloading of textures an implementation detail. It doesn’t make sense for the engine to make assumptions about what you’re going to do with the textures. If you created the texture, you should be responsible for disposing of it. Sending it to another object (the Renderer in this case) does not relieve you of this responsibility.

@eisenpony your explanation sounds reasonable, though this is probably not documented anywhere…

What about the other use case ? A texture that is created and loaded by the engine (assigned to a sprite renderer in the editor) ?

These are also not unloaded automatically by the engine when the object they are on is destroyed.

Is this also a correct behaviour ?

That seems a little more obscure because I think a lot of people may not realize they need to deal with loaded textures like this. However, the same argument applies.

If I am using Instantiate to create a clone of a prefab, it would be a nice performance gain to have the required textures in memory until I’ve reached the point where I no longer need to instantiate that prefab. Calling Resources.UnloadUnusedAssets() is a simple way to notify Unity that I’m done with unused textures.