Open gqf2008 opened 3 years ago
reproduces on gtk and x11 backend
minimal druid-shell only example to reproduce the leak. Interestingly in this case, gtk backend leaks but x11 backend doesn't
I ran the minimal druid-shell only example with default features (thus gtk) under valgrind --tool=massif
and clicked the window repeatedly. Resulting memory usage graph looks like this:
MB
142.8^ #
| @@#
| @ @@@@#::
| @@@: :@@@@#::
| @@@@:: :@@@@#:::
| @: :@@@@:: ::@@@@#::::
| @@@::: :@@@@:::::@@@@#::::
| @@: ::@ @:: :::@@@@:::::@@@@#::::
| @@ :: @ @ @:: : :@@@@:::::@@@@#:::::
| ::: ::@@ :: :@ @ @:: : :@@@@:::::@@@@#::::::
| @@: :: :: @@ ::::@ @ @:: : :@@@@:::::@@@@#::::::
| @:@ :@ : : :: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@
| @@:@: ::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@
| @@@@:@: :::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
| ::: @@ @@:@:::::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
| ::::: @@ @@:@:::::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
| :::::::@@ @@:@:::::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
| @:::::::@@ @@:@:::::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
| @:::::::@@ @@:@:::::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
| @@@:::::::@@ @@:@:::::@ : : ::: @@ ::::@ @ @:: : :@@@@:::::@@@@#:::::@:
0 +----------------------------------------------------------------------->Gi
0 21.94
I'd say that the above indicates that druid-shell is leaking gtk widgets. 20 MB for GtkCssStyle
instances seems excessive. 5 MB for ApplicationWindow
instances also seems suspicious... And another 2 MB for DrawingArea
instances.
The following seems like a hint at where the leak is coming from. An Arc
that is never freed (but it could also be that this dump is just taken at a bad moment, but that means at most 2k windows being open. Dunno if 2 MB / 2k = 2 KB per window is realistic.)
->01.78% (2,660,704B) 0x1A6AEB: alloc::alloc::alloc (alloc.rs:86)
| ->01.78% (2,660,704B) 0x1A6B76: alloc::alloc::Global::alloc_impl (alloc.rs:166)
| ->01.78% (2,660,704B) 0x1A6D99: <alloc::alloc::Global as core::alloc::Allocator>::allocate (alloc.rs:226)
| ->01.78% (2,660,704B) 0x1A6A4C: alloc::alloc::exchange_malloc (alloc.rs:316)
| ->01.38% (2,065,488B) 0x1A8E7A: alloc::sync::Arc<T>::new (sync.rs:345)
| | ->01.38% (2,065,488B) 0x1CE096: druid_shell::backend::gtk::window::WindowBuilder::build (window.rs:380)
| | ->01.38% (2,065,488B) 0x1ADD64: druid_shell::window::WindowBuilder::build (window.rs:521)
The line number is let win_state = Arc::new(state);
. Not really that helpful.... Well, actually:
https://github.com/linebender/druid/blob/3790463cf4e724719dc0c1867afe59c3f2d22b3b/druid-shell/src/backend/gtk/window.rs#L380-L389
This is by design?! WindowState
instances may only be destroyed during shutdown?
This is by design?! WindowState instances may only be destroyed during shutdown?
I think it is just accidental, WindowState
should be destroyed after closing the window.
WindowState should be destroyed after closing the window.
Sounds like the Arc
should not be kept until shutdown
on gtk_app()
, but instead the delete_event
on the window. Something like this:
let keep_everything_alive = Option(Arc::clone(&win_state))`;
win_state
.window
.connect_delete_event(clone!(handle => move |_widget, _ev| {
if let Some(state) = handle.state.upgrade() {
state.with_handler(|h| h.request_close());
let closing = state.closing.get();
if closing { keep_everything_alive.take(); }
Inhibit(!closing)
} else {
Inhibit(false)
}
}));
It was changed from window.connect_destroy
to app.connect_shutdown
in https://github.com/linebender/druid/commit/79a80df5a625f578b0fe5abab7e993b100eb538b
Yeah, well, great commit message. And that commit comes from #152 "Fix typo". So apparently this was only ever a typo...
Also, The comment says "ties a clone of ArcApplication
. So probably the commit was just a misunderstanding of semantics.
multiwin example,click “New window” and then close, repeat it to reproduce.