not-fl3 / macroquad

Cross-platform game engine in Rust.
Apache License 2.0
3.31k stars 323 forks source link

Texture2D memory leak #635

Open sloganking opened 1 year ago

sloganking commented 1 year ago

In macroquad v4.3.23 Texture2D types are never removed from memory.

Memory steadily grows until system crash when repeatedly converting an Image into a Texture2D in a loop. Even though the Texture2D is dropped at the end of each loop.

image

Memory does not grow when the macroquad program is closed or my Images are never converted to Texture2Ds image

Per https://github.com/not-fl3/macroquad/issues/421#issuecomment-1666622124, is this issue fixed but just not pushed to a crates.io release yet?

Afrovis commented 11 months ago

I'm having an issue that I believe is related when calling get_screen_data() in my render loop (for image saving per frame). Not fixed in 0.4.4 yet.

eboatwright commented 10 months ago

This is a problem in my project as well, I'm making a pixel art game, but I still want the window resizable, so every frame I'm creating a render_target and a Camera2D every frame, with the current resolution. But yeah, while running the program my memory usage slowly increases, and eventually my computer crashes (On Ubuntu 22.04, using the latest version "0.4.4")

mandroll commented 8 months ago

I also have this issue. Here is a minimal reproducer:

use macroquad::prelude::*;

#[macroquad::main("Texture test")]
async fn main() {
    let texture_size: u32= 64 * 16;
    loop {
        let render_target = render_target(texture_size, texture_size);
        next_frame().await;
    }
}

Another user on Mac claims the issue does not happen for them, suggesting it may be platform-specific. In my case, I am on Windows 10.

mandroll commented 8 months ago

I can confirm the bug is still present on HEAD. I have tested with:

[package]
name = "texture-memory"
version = "0.1.0"
edition = "2021"

[dependencies]
macroquad = { git = "https://github.com/not-fl3/macroquad.git", branch = "master" }
mandroll commented 8 months ago

Here is a dhat heap profile of the above program: https://gist.github.com/mandroll/02b19220221bc81a1f83d2d299914a32

ElnuDev commented 6 months ago

I also have this issue. Here is a minimal reproducer:

use macroquad::prelude::*;

#[macroquad::main("Texture test")]
async fn main() {
    let texture_size: u32= 64 * 16;
    loop {
        let render_target = render_target(texture_size, texture_size);
        next_frame().await;
    }
}

Another user on Mac claims the issue does not happen for them, suggesting it may be platform-specific. In my case, I am on Windows 10.

I'm getting this exact same problem with initializing a RenderTarget every frame due to the wrapped Texture2D. This is a really serious issue because it will always cause crashes due to running out of memory. Is there any news on this? @not-fl3

not-fl3 commented 6 months ago

Despite the bug, allocating textures and especially render targets each frame would never work really well. Its a really expensive procedure and there are so many things that could go wrong with that approach.

Not like this bug is not worth to be fixed or anything, just a side note :)

ElnuDev commented 6 months ago

Thanks! I made a mistake in my implementation originally that gave me the false impression that RenderTargets can't be reused, now I'm reusing the same RenderTarget and the memory is leak is of course gone. That being said, this summer when I have the time, I might look into this bug and see if I can find a fix.

eboatwright commented 6 months ago

Despite the bug, allocating textures and especially render targets each frame would never work really well. Its a really expensive procedure and there are so many things that could go wrong with that approach.

Not like this bug is not worth to be fixed or anything, just a side note :)

Is there a way to resize a previously created RenderTarget?

InnocentusLime commented 3 weeks ago

It doesn't seem to leak from just loading the textures now. However, it seems the leaks still happens when build_texture_atlas() is involved.

I believe that is because the texture atlas ends up holding strong references to the textures and never gets garbage-collected

#[macroquad::main("Leak?")]
async fn main() {
    loop {
        let t = load_texture("texture.png").await.unwrap();

        build_textures_atlas();

        next_frame().await;
    }
}