Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

~~Text~~ Image leaks memory #111

Closed
ozkriff opened this issue Jul 20, 2017 · 7 comments

Comments

@ozkriff
Copy link
Contributor

commented Jul 20, 2017

Example:

extern crate ggez;
extern crate rand;

use std::time::Duration;
use rand::{Rng, thread_rng};
use ggez::conf;
use ggez::event;
use ggez::{GameResult, Context};
use ggez::graphics;

struct MainState {
    font: graphics::Font,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let s = MainState {
            font: graphics::Font::new(ctx, "/DejaVuSerif.ttf", 48)?,
        };
        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut Context, _dt: Duration) -> GameResult<()> {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::clear(ctx);
        let str = format!("rand: {}", thread_rng().gen_range(0, 6));
        let text = graphics::Text::new(ctx, &str, &self.font)?;
        let dest_point = graphics::Point::new(
            text.width() as f32 / 2.0 + 10.0,
            text.height() as f32 / 2.0 + 10.0,
        );
        graphics::draw(ctx, &text, dest_point, 0.0)?;
        graphics::present(ctx);
        Ok(())
    }
}

pub fn main() {
    let c = conf::Conf::new();
    let ctx = &mut Context::load_from_conf("helloleak", "ozkriff", c).unwrap();
    let state = &mut MainState::new(ctx).unwrap();
    if let Err(e) = event::run(ctx, state) {
        println!("Error encountered: {}", e);
    } else {
        println!("Game exited cleanly.");
    }
}

~30Kb per second on my machine

@icefoxen

This comment has been minimized.

Copy link
Contributor

commented Jul 20, 2017

Coooooool. I love things that should be impossible.

One possible bisection: Check whether creating an Image leaks memory as well, since Text uses that to store the texture data.

@icefoxen

This comment has been minimized.

Copy link
Contributor

commented Jul 20, 2017

Confirmed, though it's more like 5-10 kb per second on my system; about the same results in both debug and release mode. Measured with watch 'ps aux | grep testprogram'

Persists even when you don't actually draw the text. Valgrind makes the test program segfault for some reason (booo).

Replacing the render-text code with just loading an Image gets about the same behavior, so there's the root. The memory consumption appears about the same even regardless of the size of the Image (dragon1.png vs. player.png, 83 kb vs <1 kb). This is rendering at 60 fps and so each load leaks something like 0.25 kb of memory, which is really quite small; it's probably not the image data itself being leaked but some buffer or descriptor inside of gfx-rs.

Might be this? gfx-rs/gfx#1054 Only gfx-rs issue that looks likely to be related.

To do: Check with newer versions of gfx-rs, maybe the leak has been fixed already.

@icefoxen icefoxen changed the title Text leaks memory ~Text~ Image leaks memory Jul 20, 2017

@icefoxen icefoxen changed the title ~Text~ Image leaks memory ~~Text~~ Image leaks memory Jul 20, 2017

@iremaildb

This comment has been minimized.

Copy link

commented Jul 22, 2017

I have a similar bug, except occasionally the GPU complains that it has run out of memory, as well so I was thinking that texture handles were getting leaked. FWIW, this is usually ~13min into running my game. What happens is that the text starts failing to render (no errors, despite .unwrap() and ? in all the right places) [the rest of my game is just colored rectangles for now, so they continue working fine] and then a few seconds later, it will occasionally crash with "intel_do_flush_locked" (driver errors).

I tried upgrading a checked-out copy of ggez to gfx = "^0.16" with no other changes, and this did not make either issue go away.

Out of curiosity, how are resources handled in ggez/gfx? There doesn't appear to be any implementations of Drop in ggez, which means the default drop handlers do the work. I tried looking further into gfx, but got pretty stuck. Is one of those Image types secretly a Rc<something_important>?

@icefoxen

This comment has been minimized.

Copy link
Contributor

commented Jul 22, 2017

Yeah most things that are GPU resources (textures, buffers, etc) in gfx-rs generally are just Arc'ed handles.

ggez defers almost all actual resource management to the user; it is very seldom that it actually stores something in the Context. Upon inspection the only place where it might store additional info per Image is in the SamplerCache, but printing out the size of it when creating an Image shows that's not it.

@igowen

This comment has been minimized.

Copy link

commented Jul 24, 2017

(disclaimer: I'm relatively new to Rust, so I could be completely wrong)

it looks like the problem is that Image::make_raw() calls gfx_device_gl::Factory::create_texture_immutable_u8(), which subsequently calls gfx_device_gl::Factory::create_texture_raw(). That last one allocates a texture and stores it (wrapped in an Arc) inside the factory's handle manager. There doesn't seem to be any way to clean it up after you're done with it, short of clear()ing the entire manager (which will jettison everything).

@icefoxen

This comment has been minimized.

Copy link
Contributor

commented Jul 24, 2017

afaict these resources should be released with the Device::cleanup() call, which gets called in ggez::graphics::present(). This seems to be implemented here: https://github.com/gfx-rs/gfx/blob/master/src/backend/gl/src/lib.rs#L976 ; the Factory.share field is Rc'ed and presumably, well, shared, with the Device (which in this case is the same as the CommandBuffer? idk, we're starting to get into the trait-salad that makes gfx hard to navigate unless you know how the pieces fit together already).

@icefoxen

This comment has been minimized.

Copy link
Contributor

commented Jul 24, 2017

I've finally gotten around to confirming this using bare gfx-rs and punted the bug upstream: gfx-rs/gfx#1395 . Further tracking or troubleshooting should please happen there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.