Bug 547227 - [GTK3] Group widget causes memory leak and slowdown
Summary: [GTK3] Group widget causes memory leak and slowdown
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.12   Edit
Hardware: PC Linux
: P3 major (vote)
Target Milestone: 4.13 M1   Edit
Assignee: Eric Williams CLA
QA Contact:
URL:
Whiteboard: RHT
Keywords: triaged
Depends on:
Blocks:
 
Reported: 2019-05-13 11:48 EDT by Patrick Tasse CLA
Modified: 2019-07-29 15:59 EDT (History)
3 users (show)

See Also:


Attachments
Snippet (2.19 KB, text/x-java)
2019-05-13 11:48 EDT, Patrick Tasse CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Patrick Tasse CLA 2019-05-13 11:48:30 EDT
Created attachment 278590 [details]
Snippet

SWTBot unit tests have never worked properly on GTK3, so they were always run with GTK2. Starting with 2018-12, SWTBot unit tests are no longer successful since GTK2 support is removed. The unit tests get progressively slower until the whole build fails with Tycho return code 137.

We've discovered that the issue seems to be with the Group widget, which is used extensively in the SWT Control Example shell in SWTBot unit tests.

It appears that creating and disposing Group widgets gets linearly slower, until the system finally kills the build, presumably running out of memory.

The included snippet shows the issue. Running it once for every SWTBot unit test class on the latest CI infrastructure gives the following output:

https://ci.eclipse.org/swtbot/job/swtbot-gerrit/1035/console

1st unit test class:

15:08:26 gtk version: 3.22.30
15:08:26 
15:08:26 shell.dispose() for Shell {} with 400 Composite [1]...	  10 ms =
15:08:26 shell.dispose() for Shell {} with 400 Composite [2]...	  11 ms ==
15:08:26 shell.dispose() for Shell {} with 400 Composite [3]...	  12 ms ==
15:08:26 shell.dispose() for Shell {} with 400 Composite [4]...	  13 ms ==
15:08:26 shell.dispose() for Shell {} with 400 Composite [5]...	  10 ms =
15:08:26 shell.dispose() for Shell {} with 400 Composite [6]...	  11 ms ==
15:08:26 shell.dispose() for Shell {} with 400 Composite [7]...	  13 ms ==
15:08:26 shell.dispose() for Shell {} with 400 Composite [8]...	  11 ms ==
15:08:26 shell.dispose() for Shell {} with 400 Composite [9]...	  11 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [10]...  11 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [11]...  11 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [12]...  10 ms =
15:08:27 shell.dispose() for Shell {} with 400 Composite [13]...  12 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [14]...  14 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [15]...  12 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [16]...  11 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [17]...  12 ms =
15:08:27 shell.dispose() for Shell {} with 400 Composite [18]...  12 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [19]...  11 ms ==
15:08:27 shell.dispose() for Shell {} with 400 Composite [20]...  11 ms ==
15:08:27 
15:08:28 shell.dispose() for Shell {} with 400 Group [1]...	  36 ms ====
15:08:28 shell.dispose() for Shell {} with 400 Group [2]...	  38 ms ====
15:08:28 shell.dispose() for Shell {} with 400 Group [3]...	  39 ms ====
15:08:28 shell.dispose() for Shell {} with 400 Group [4]...	  43 ms =====
15:08:29 shell.dispose() for Shell {} with 400 Group [5]...	  46 ms =====
15:08:29 shell.dispose() for Shell {} with 400 Group [6]...	  48 ms =====
15:08:29 shell.dispose() for Shell {} with 400 Group [7]...	  53 ms ======
15:08:29 shell.dispose() for Shell {} with 400 Group [8]...	  54 ms ======
15:08:30 shell.dispose() for Shell {} with 400 Group [9]...	  57 ms ======
15:08:30 shell.dispose() for Shell {} with 400 Group [10]...	  59 ms ======
15:08:30 shell.dispose() for Shell {} with 400 Group [11]...	  62 ms =======
15:08:30 shell.dispose() for Shell {} with 400 Group [12]...	  64 ms =======
15:08:31 shell.dispose() for Shell {} with 400 Group [13]...	  67 ms =======
15:08:31 shell.dispose() for Shell {} with 400 Group [14]...	  69 ms =======
15:08:31 shell.dispose() for Shell {} with 400 Group [15]...	  75 ms ========
15:08:31 shell.dispose() for Shell {} with 400 Group [16]...	  74 ms ========
15:08:32 shell.dispose() for Shell {} with 400 Group [17]...	  77 ms ========
15:08:32 shell.dispose() for Shell {} with 400 Group [18]...	  78 ms ========
15:08:32 shell.dispose() for Shell {} with 400 Group [19]...	  81 ms =========
15:08:32 shell.dispose() for Shell {} with 400 Group [20]...	  84 ms =========
15:08:32 

:
:
:

10th unit test class:

15:20:56 gtk version: 3.22.30
15:20:56 
15:20:56 shell.dispose() for Shell {} with 400 Composite [1]...	  12 ms ==
15:20:56 shell.dispose() for Shell {} with 400 Composite [2]...	  13 ms ==
15:20:56 shell.dispose() for Shell {} with 400 Composite [3]...	  12 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [4]...	  12 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [5]...	  11 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [6]...	  12 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [7]...	  11 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [8]...	  13 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [9]...	  12 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [10]...  12 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [11]...  11 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [12]...  12 ms ==
15:20:57 shell.dispose() for Shell {} with 400 Composite [13]...  11 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [14]...  13 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [15]...  11 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [16]...  12 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [17]...  11 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [18]...  12 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [19]...  12 ms ==
15:20:58 shell.dispose() for Shell {} with 400 Composite [20]...  11 ms ==
15:20:58 
15:21:01 shell.dispose() for Shell {} with 400 Group [1]...	2786 ms =======================================================================================================================================================================================================================================================================================
15:21:04 shell.dispose() for Shell {} with 400 Group [2]...	2798 ms ========================================================================================================================================================================================================================================================================================
15:21:07 shell.dispose() for Shell {} with 400 Group [3]...	2818 ms ==========================================================================================================================================================================================================================================================================================
15:21:10 shell.dispose() for Shell {} with 400 Group [4]...	2837 ms ============================================================================================================================================================================================================================================================================================
15:21:14 shell.dispose() for Shell {} with 400 Group [5]...	2851 ms ==============================================================================================================================================================================================================================================================================================
15:21:17 shell.dispose() for Shell {} with 400 Group [6]...	2865 ms ===============================================================================================================================================================================================================================================================================================
15:21:20 shell.dispose() for Shell {} with 400 Group [7]...	2853 ms ==============================================================================================================================================================================================================================================================================================
15:21:23 shell.dispose() for Shell {} with 400 Group [8]...	2890 ms =================================================================================================================================================================================================================================================================================================
15:21:26 shell.dispose() for Shell {} with 400 Group [9]...	2892 ms ==================================================================================================================================================================================================================================================================================================
15:21:29 shell.dispose() for Shell {} with 400 Group [10]...	2916 ms ====================================================================================================================================================================================================================================================================================================
15:21:32 shell.dispose() for Shell {} with 400 Group [11]...	2913 ms ====================================================================================================================================================================================================================================================================================================
15:21:35 shell.dispose() for Shell {} with 400 Group [12]...	2939 ms ======================================================================================================================================================================================================================================================================================================
15:21:39 shell.dispose() for Shell {} with 400 Group [13]...	3047 ms =================================================================================================================================================================================================================================================================================================================
15:21:42 shell.dispose() for Shell {} with 400 Group [14]...	3000 ms ============================================================================================================================================================================================================================================================================================================
15:21:45 shell.dispose() for Shell {} with 400 Group [15]...	3032 ms ================================================================================================================================================================================================================================================================================================================
15:21:48 shell.dispose() for Shell {} with 400 Group [16]...	2982 ms ===========================================================================================================================================================================================================================================================================================================
15:21:52 shell.dispose() for Shell {} with 400 Group [17]...	2987 ms ===========================================================================================================================================================================================================================================================================================================
15:21:55 shell.dispose() for Shell {} with 400 Group [18]...	3016 ms ==============================================================================================================================================================================================================================================================================================================
15:21:58 shell.dispose() for Shell {} with 400 Group [19]...	3017 ms ==============================================================================================================================================================================================================================================================================================================
15:22:01 shell.dispose() for Shell {} with 400 Group [20]...	3031 ms ================================================================================================================================================================================================================================================================================================================
Comment 1 Patrick Tasse CLA 2019-05-13 11:57:15 EDT
Forgot to add that the slowdown occurs in the call to OS._gtk_widget_destroy() as described in https://bugs.eclipse.org/bugs/show_bug.cgi?id=506807#c0
Comment 2 Alexander Kurtakov CLA 2019-05-13 12:15:18 EDT
Eric please investigate.
Comment 3 Eric Williams CLA 2019-05-13 13:00:56 EDT
Can you reproduce the slowdown locally as well? Or only on CI machines?
Comment 4 Eric Williams CLA 2019-05-13 13:09:23 EDT
Looking at the code in Group, it appears that Group.releaseWidget() does not call g_object_unref() on clientHandle. If I had to guess, this is causing the memory leak.
Comment 5 Patrick Tasse CLA 2019-05-13 13:22:41 EDT
Yes, we can reproduce locally on Ubuntu 14.04 GTK 3.10.8 and Ubuntu 16.04 GTK 3.20.8.

I tried adding the following line to Group.releaseWidget():

	if (clientHandle != 0) OS.g_object_unref (clientHandle);

It results on spamming the console with errors:

(SWT:5295): Gtk-CRITICAL **: gtk_widget_get_realized: assertion 'GTK_IS_WIDGET (widget)' failed

(SWT:5295): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer

(SWT:5295): GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(SWT:5295): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

This was on GTK 3.10.8.
Comment 6 Patrick Tasse CLA 2019-05-17 16:02:41 EDT
Any update on this?

Unless it is fixed, the SWTBot unit test infrastructure is stuck on 2018-09/GTK2.
Comment 7 Eric Williams CLA 2019-05-17 16:13:09 EDT
(In reply to Patrick Tasse from comment #6)
> Any update on this?
> 
> Unless it is fixed, the SWTBot unit test infrastructure is stuck on
> 2018-09/GTK2.

Time has by and large run out for 4.12, unless I manage to find a fix in the next week. I was busy with internal tasks this week and was not able to take a good look.

I'll make this a priority for the next week. If it can't be fixed by then, it will have high priority for 4.13.
Comment 9 Eric Williams CLA 2019-06-19 10:46:45 EDT
(In reply to Eclipse Genie from comment #8)
> Gerrit change https://git.eclipse.org/r/144396 was merged to [master].
> Commit:
> http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/
> ?id=1a722935d5c4937bbfa79b2970b3574752be9070

In master now.
Comment 10 Patrick Tasse CLA 2019-06-21 10:59:22 EDT
Hi Eric,

Now that you understand the specifics of this issue, can you think of any workaround that SWTBot could do to have successful unit testing on 2018-12, 2019-03 and 2019-06 targets?
Comment 11 Eric Williams CLA 2019-07-10 11:29:27 EDT
Verified in I20190710-0610.