Memory leaks as hell

I start writing an app using Pison, and I found that my PC freezes in few seconds after my app run because memory is all gone.

I reduced app to the very small example, and I can't understand where memory goes.

Here it is. If you uncomment texture.update it hogs all memory (gigabytes of it!) in seconds.

extern crate piston_window;
extern crate image as im;

use piston_window::*;
use piston::event_loop::Events;

fn main() {
    let x = 1920;
    let y  = 1080;
    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow =
        WindowSettings::new("test", (x, y))
        .exit_on_esc(true)
        .graphics_api(opengl)
        .build()
        .unwrap();
    let mut texture_context = TextureContext {
        factory: window.factory.clone(),
        encoder: window.factory.create_command_buffer().into()
    };
    let mut events = Events::new(EventSettings::new().lazy(false));
    let buf = im::ImageBuffer::new(x, y);
    let mut texture: G2dTexture = Texture::from_image(
                &mut texture_context,
                &buf,
                &TextureSettings::new()
            ).unwrap();
    while let Some(e) = events.next(&mut window) {
        if let Some(_) = e.render_args() {
            // texture.update(&mut texture_context, &buf).unwrap();
            window.draw_2d(&e, |c, g, _device| {
                    image(&texture, c.transform, g);
            });
        }
    }
}

How can it be that memory is leaking?

If you're on Linux, you can see what's leaking with Valgrind's memcheck. It's compatible with Rust.

2 Likes

My guess would be that the texture updates are queued into some staging buffer which is never flushed or reused. Leaking ~8MB per frame will quickly fill up memory. I don't know enough about this specific API to say for sure, or how to avoid it, though.

1 Like

Thank you for idea. I've run valgrind, it sees huge allocated memory, but only 305,761 bytes leaked.

The single thing I see (I don't know if this matter or not) is this:

==9763== Conditional jump or move depends on uninitialised value(s)
==9763==    at 0x7494B24: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.450.57)

It's easy to point to nvidia and claim they leaks memory, but the leak is crazy (like 16Gb in 20 seconds) so I doubt they are real culprit here.

draw_2d already does nothing when e.render_args() is None.

https://docs.rs/piston_window/0.112.0/src/piston_window/lib.rs.html#277-298

1 Like

For what it's worth, I can reproduce this leak. Since you have a reproducible test case, I would report this to the Piston or gfx issue tracker.

1 Like

Thank you, I've reported it here: https://github.com/PistonDevelopers/piston/issues/1357

4 Likes

After some example rereading, I've realized, I trimmed away from examples one important line:

texture_context.encoder.flush(_device);

So, the proper draw_2d function is

        if let Some(_) = e.render_args() {
            texture.update(&mut texture_context, &buf).unwrap();
            window.draw_2d(&e, |c, g, device| {
                    texture_context.encoder.flush(device);
                    image(&texture, c.transform, g);
            });
        }

It completely stopped memory leak.

3 Likes

Very interesting. I found (after I fixed memory leak I've complained about) that if I do window.draw_2d on empty events it bumps my memory consumption about 10 fold. It's not leaking, but application is consuming a lot of CPU and memory, so this if is very important for performance.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.