Memory Leak on RenderTexture

Hey everyone,

It seems that it’s a common topic, but my googling has not resulted in a solution so far, so I hope someone here can enlighten me :slight_smile:

I have a function that captures the view of a camera and sends the image on for further processing:

    Texture2D CamCapture()
    {      
        renderTexture = RenderTexture.GetTemporary((int)width, (int)height, 24);
        vehicleCamera.targetTexture = renderTexture;
        RenderTexture.active = renderTexture;
        vehicleCamera.Render();

        Texture2D myTexture2D = new Texture2D(renderTexture.width, renderTexture.height,TextureFormat.RGB24, false);       
        myTexture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
       
        RenderTexture.ReleaseTemporary(renderTexture);

        return myTexture2D;
    }

This gets called a few times every second, and I can see that my memory increases over time. If anyone could point out what I’m missing that would be really helpful.

Probably a Destroy(myTexture2D);

See here textures - Issue with Texture2D memory leak in Unity - Game Development Stack Exchange

Thanks a lot @c0d3_m0nk3y this helped a lot. If I understand correctly creating the local Texture2D without destroying it created issues (and I couldn’t destroy it since I needed the return value).

With the following implementation I no longer see the memory leak behavior (very well possible that I’m still doing some unnecessary or suboptimal things, let me know if anything pops out :slight_smile: ):

    private RenderTexture renderTexture;
    private Texture2D cameraCapture;

    void OnEnable() {
        if (cameraCapture == null) {
            cameraCapture = new Texture2D((int)width, (int)height, TextureFormat.RGB24, false);
        }
    }

  void Update()
    {
        CamCapture(cameraCapture);
// do something with cameraCapture
    }

    void CamCapture(Texture2D destination)
    {     
        renderTexture = RenderTexture.GetTemporary((int)width, (int)height, 24);
        vehicleCamera.targetTexture = renderTexture;
        RenderTexture.active = renderTexture;
        vehicleCamera.Render();
        destination.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        destination.Apply();
      
        RenderTexture.ReleaseTemporary(renderTexture);
        RenderTexture.active = null;
    }

    // Clean up after ourselves when no longer needed.
    void OnDestroy() {
        if (cameraCapture != null) {
            Destroy(cameraCapture);
            cameraCapture = null;
        }
    }

Looks good. Just be aware that reading pixels back from the GPU is extremely slow. It’s fine for taking a screenshot but I wouldn’t do it every frame. The CPU is up to 3 frames ahead of the GPU, so fetching data from the GPU creates a stall.

If you really need to do it every frame, there is a way to do it asynchronously, I think.

Ah thanks, good to know! I’m not calling it on every frame in my application (I simplified it here), it’s running at 10 Hz right now, but I’ll keep an eye on the performance hit it incurs.