After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 775126 - memory leak in gdk_wayland_window_ensure_cairo_surface
memory leak in gdk_wayland_window_ensure_cairo_surface
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: Wayland
3.22.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2016-11-26 07:59 UTC by Timm Bäder
Modified: 2017-09-26 19:26 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Plug the memory leak (1.92 KB, patch)
2017-09-22 11:07 UTC, Daniel Elstner
accepted-commit_now Details | Review

Description Timm Bäder 2016-11-26 07:59:49 UTC
Not sure if this is 3.89 only but I didn't see it in 3.22.

I see a fair amount of this when running the current gtk4-widget-factory in valgrind:

==2847== 24,472 (14,592 direct, 9,880 indirect) bytes in 38 blocks are definitely lost in loss record 21,517 of 21,537
==2847==    at 0x4C2AB8D: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2847==    by 0x73B05B7: _cairo_image_surface_create_for_pixman_image (cairo-image-surface.c:184)
==2847==    by 0x73B0B5E: _cairo_image_surface_create_with_pixman_format (cairo-image-surface.c:353)
==2847==    by 0x73B0BFF: cairo_image_surface_create (cairo-image-surface.c:399)
==2847==    by 0x4EE9692: gdk_wayland_window_ensure_cairo_surface (gdkwindow-wayland.c:818)
==2847==    by 0x4EE9867: gdk_wayland_window_ref_cairo_surface (gdkwindow-wayland.c:858)
==2847==    by 0x4ED7E23: gdk_window_ref_impl_surface (gdkwindow.c:2595)
==2847==    by 0x4ED7DCF: gdk_window_get_content (gdkwindow.c:2585)
==2847==    by 0x4ED82DA: gdk_window_begin_paint_internal (gdkwindow.c:2720)
==2847==    by 0x4ED89B9: gdk_window_begin_draw_frame (gdkwindow.c:2908)
==2847==    by 0x4FBC268: gtk_widget_render (gtkwidget.c:15744)
==2847==    by 0x51AEB57: gtk_main_do_event (gtkmain.c:1787)
==2847==    by 0x4F0EE7B: _gdk_event_emit (gdkevents.c:73)
==2847==    by 0x4ED9737: _gdk_window_process_updates_recurse_helper (gdkwindow.c:3443)
==2847==    by 0x4ED9926: _gdk_window_process_updates_recurse (gdkwindow.c:3495)
==2847==    by 0x4EE5DB2: gdk_window_impl_process_updates_recurse (gdkwindowimpl.c:333)
==2847==    by 0x4ED9B2C: gdk_window_process_updates_internal (gdkwindow.c:3570)
==2847==    by 0x4ED9FF8: gdk_window_process_updates_with_mode (gdkwindow.c:3767)
==2847==    by 0x4EE4A05: gdk_window_paint_on_clock (gdkwindow.c:10424)
==2847==    by 0xA00DBBF: g_cclosure_marshal_VOID(intXX_t &&) volatile (gmarshal.c:875)
==2847==    by 0xA00EA5D: g_closure_invoke (gclosure.c:804)
==2847==    by 0x9FEFFC0: signal_emit_unlocked_R.lto_priv.369 (gsignal.c:3635)
==2847==    by 0x9FF39E2: g_signal_emit_valist (gsignal.c:3391)
==2847==    by 0x9FF3F21: g_signal_emit (gsignal.c:3447)
==2847==    by 0x4F133B6: _gdk_frame_clock_emit_paint (gdkframeclock.c:640)
==2847==    by 0x4F13F13: gdk_frame_clock_paint_idle (gdkframeclockidle.c:430)
==2847==    by 0x4EFF40F: gdk_threads_dispatch (gdk.c:630)
==2847==    by 0xA4A3021: g_timeout_dispatch.lto_priv.209 (gmain.c:4674)
==2847==    by 0xA4A934D: g_main_dispatch.lto_priv.1021 (gmain.c:3203)
==2847==    by 0xA4A201B: g_main_context_dispatch (gmain.c:3856)
==2847==    by 0xA4A21FF: g_main_context_iterate (gmain.c:3929)
==2847==    by 0xA4A22C3: g_main_context_iteration (gmain.c:3990)
==2847==    by 0x9492921: g_application_run (gapplication.c:2381)
==2847==    by 0x40670D: main (widget-factory.c:1942)
Comment 1 Olivier Fourdan 2016-11-30 16:47:00 UTC
I don't see that in 3.22 either.
Comment 2 Daniel Elstner 2017-09-22 08:22:00 UTC
I see it in 3.22.21 in an application that uses OpenGL for an animation. The thing is leaking like a sieve.

I investigated a bit, and this code in gdk_wayland_window_ensure_cairo_surface() looks kinda fishy to me:

  /* If we are drawing using OpenGL then we only need a logical 1x1 surface. */
  if (impl->display_server.egl_window)
    {
      if (impl->staging_cairo_surface &&
          _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
        cairo_surface_destroy (impl->staging_cairo_surface);

      impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                                impl->scale,
                                                                impl->scale);
      cairo_surface_set_device_scale (impl->staging_cairo_surface,
                                      impl->scale, impl->scale);
    }
  else if (!impl->staging_cairo_surface)

Note how cairo_surface_destroy() is only called if _gdk_wayland_is_shm_surface() is TRUE, but the 1x1 dummy surface is recreated in every single drawing call.

As I said, the thing really does leak like a sieve. Several megabytes per minute, so it's pretty serious. I suspect that using GL is a precondition for reproducing this with GTK+ 3.22.
Comment 3 Daniel Elstner 2017-09-22 11:07:01 UTC
Created attachment 360253 [details] [review]
Plug the memory leak

The attached patch fixes the problem for me. I applied it to my distro GTK+ 3.22 package and the leak is gone. I haven't tested on master but it looks like the code didn't change at all, so it should apply.

I can commit it myself if I get the go-ahead.
Comment 4 Daniel Elstner 2017-09-26 18:37:42 UTC
Pingaling? It would be really nice to get this in, since the leak is really serious when using GTK+ 3.22 on Wayland with GtkGLArea.
Comment 5 Carlos Garnacho 2017-09-26 18:56:52 UTC
Review of attachment 360253 [details] [review]:

Looks good to me.
Comment 6 Daniel Elstner 2017-09-26 19:02:14 UTC
Great. So shall I push to 3.22, master, or both?
Comment 7 Daniel Elstner 2017-09-26 19:16:30 UTC
Pushed to both branches. Thanks!