I have setup a photoshoot scene where if the user enters playmode, screenshots of hundreds of objects is made.
This currently works like this:
renderTexture and texture2D are global variables for reusing.
The following loop is executed in a coroutine where WaitForNextFrame() is called multiple times:
A gameobject is instantiated in a place where the camera can see it.
Bounding box of the object is found, which is used for cropping
new RenderTexture with the height and width of the camera with is instantiated.
new Texture2D with the height and width of the bounding box is instantiated.
renderTexture.Create() is called, RenderTexture.active = renderTexture, camera.targetTexture = renderTexture.
camera.Render() is called, texture2D.ReadPixels(), texture2D.Apply().
The instantiated gameobject in step 1 is Destroyed.
Repeat
This however causes memory leak. I am destroying the render texture, texture 2D and the gameobject, but some things still remain in the memory.
While looking at the profiler, I noticed that the only thing under the Memory tab that remained the same, was GameObjects in Scene (this is okay because I destroy one and add another). However, everything else goes up: Total Object Count, Total Objects in Scene, Assets, Textures, Meshes, Materials.
When I look at the more detailed Memory tab, then under Assets, Texture2D goes up but never down. Same with meshes. In the Not Saved category, the amount of RenderTextures also goes up.
Can somebody explain to me what can I do the fix the situation? I tried not creating new render textures with new RenderTexture(), and instead tried to just set the width and height but this is not supported.
It’s a good idea to use RenderTexture.GetTemporary when working with rendertextures with a short lifespan.
Additionally, I’m curious why you’re calling Resources.UnloadUnusedAssets before you destroy the gameobject. Clearly the resources are still in use, they’re being used on the gameobject!
I will try the GetTemporary method. As yes, the RenderTextures were piling up. But unfortunately, the textures, which do not get destroyed is still a problem.
It does not matter much where I call the UnloadUnusedAssets, because with the next loop iteration, the current object will still get destroyed. Yes, of course it makes more sens to use it after destroying the current item, which I will do after refactoring.
The created prefab instance life cycle goes like this:
In Awake I already load all the possible prefabs.
1.1) Get the file path and use AssetDatabase.LoadAssetAtPath()
1.2) Object is cast to GameObject and I check for an attached component. If it does exist, the gameobject is put into a dictionary with its category as key.
At this point, all these prefabs are not instantiated in the scene.
Loop through all the possible categories and get the gameobject from the dictionary.
Destroy the previous gameobject if it exists (on first loop iteration, this step is skipped).
Instantiate the gameobject that we got from the dictionary.
Make the screenshot, Destroy the Instantiated gameobject.
If you’re doing this in edit mode, you need to use DestroyImmediate, as Destroy doesn’t work unless you’re in play mode (or build).
Otherwise, I can’t see anything blatantly wrong with your pseudo-code. I doubt that unity has a massive GC bug in it, so you’re still most likely doing something that’s preventing GC from cleaning up the resources.
The render texture and texture2D are both class variables, not scoped to the local function. So each loop iteration I re-use the same variable by using new RenderTexture on the render texture variable and when I am done, I destroy the render texture and set the variable to null.
Similar thing happens to the instantiated gameobject. I temporarily store it in a variable in a class. However after destroying the prefab I set the variable also to null.
I do not destroy or remove the class instance in which these objects (render texture, gameobjects) are temporarily stored. Could this be an issue in any way?
The editor is quite different from runtime, do you have the same issue in runtime? For example, assets may stay in memory because of the inspector or some other editor that still references it.