GNOME Bugzilla – Bug 558594
memory leak when destroying many widgets
Last modified: 2018-02-10 04:39:58 UTC
Please describe the problem: The following program creates and destroys 2000 text entries every 100ms. It takes up more and more memory /* gcc -Wall -g test.c -o test2 `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` */ #include <stdio.h> #include <stdlib.h> #include <gtk/gtk.h> GtkWidget *entry; GtkWidget *vbox; guint test_function(gpointer data){ GList *iter; GList *original_iter; iter = original_iter = gtk_container_get_children (GTK_CONTAINER (vbox)); while(iter){ GtkWidget *child; child = iter->data; iter = iter->next; gtk_container_remove(GTK_CONTAINER(vbox),child); } g_list_free(original_iter); int i; for( i = 0 ; i < 2000 ; i++){ entry = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); gtk_widget_show (entry); } return 1; } int main( int argc, char *argv[] ) { int time_interval = 100; GtkWidget *window; gtk_init (&argc, &argv); /* create a new window */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100); gtk_window_set_title (GTK_WINDOW (window), "GTK Entry"); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect_swapped (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_widget_destroy), G_OBJECT (window)); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show (vbox); g_timeout_add(time_interval,(GSourceFunc) test_function,0); gtk_widget_show (window); gtk_main(); return 0; } Steps to reproduce: 1. compile the program 2. run it and run top at the same time 3. see how much memory it is taken up in top Actual results: the memory usage keeps going up (I've gotten it up to 64 megs) Expected results: the memory usage is constant Does this happen every time? yes Other information: I've had others follow these steps, with the same result
Please use valgrind to find concrete evidence of memory leaks with your test programme. See http://live.gnome.org/Valgrind for how to use it with gnome.
Created attachment 121697 [details] valgrind output
summary of the valgrind output: ==12756== LEAK SUMMARY: ==12756== definitely lost: 11,676 bytes in 51 blocks. ==12756== indirectly lost: 26,020 bytes in 1,289 blocks. ==12756== possibly lost: 800 bytes in 20 blocks. ==12756== still reachable: 6,586,447 bytes in 151,045 blocks. ==12756== suppressed: 0 bytes in 0 blocks.
In the valgrind log, I don't see any unexpected mem leaks. (For future reference: you need to install debuginfo packages to make the valgrind output useful. No need to revalgrind here, since there are no leaks.)
Then why is top showing memory usage at 64 megs after 15 minutes (and growing) . Everyone I've asked to run this program has told me they see they're memory usage grow indefinitely in top
here's the top output from me and a fellow user: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 14073 palomer 20 0 42484 33m 5360 S 82 1.6 36:28.29 test2 24593 yziquel 25 0 183m 75m 6460 R 63 5.4 21:17.11 test2 there's definitely something fishy going on
Another top output: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 25534 thelema 20 0 161m 64m 5932 R 76 3.2 15:51.44 test2 Selected output of [pmap -d 25534]: 25534: ./test2 Address Kbytes Mode Offset Device Mapping 0000000000400000 8 r-x-- 0000000000000000 008:00004 test2 0000000000601000 4 rw--- 0000000000001000 008:00004 test2 0000000000602000 58824 rw--- 0000000000602000 000:00000 [ anon ] <SNIP> mapped: 165120K writeable/private: 59992K shared: 672K
Just a wild guess. But try to register the function with g_idle_add_full and G_PRIORITY_LOW. Maybe there are just events queuing up?
@Banjamin: that's a good thought. Turning down the event timer to 3000 ms, my computer still pegs CPU (indicating to me that the events take longer than 3s to take place. I've bumped the timer up to 30s, so now the CPU usage is about 50% - half at 100%, half at 0. we'll see what the status is after 8 hours.
here is a quote from Jean-Philippe Chancelier on the the gtk devel mailing list: Hello, I have tried your code and have changed the code to control the number of times test_function is called then I run the program through valgrind which detects memory leaks. But when count is 3,then 6, then 9 some detected leaks do not increase in size. The only part which increases is ==14007== 651,808 bytes in 636 blocks are possibly lost in loss record 139 of 141 ==14007== at 0x4004710: memalign (vg_replace_malloc.c:332) ==14007== by 0x400476A: posix_memalign (vg_replace_malloc.c:425) ==14007== by 0x4064198: (within /lib/libglib-2.0.so.0.1200.13) ==14007== by 0x4064BFB: g_slice_alloc (in /lib/libglib-2.0.so.0.1200.13) ==14007== by 0x4064D24: g_slice_alloc0 (in /lib/libglib-2.0.so.0.1200.13) ==14007== by 0xD38386: g_type_create_instance (in /lib/libgobject-2.0.so.0.1200.13) ==14007== by 0xD1FF71: (within /lib/libgobject-2.0.so.0.1200.13) ==14007== by 0xD1DBBA: g_object_newv (in /lib/libgobject-2.0.so.0.1200.13) ==14007== by 0xD1E72D: g_object_new_valist (in /lib/libgobject-2.0.so.0.1200.13) ==14007== by 0xD1E8DF: g_object_new (in /lib/libgobject-2.0.so.0.1200.13) ==14007== by 0x43C95B8: gdk_window_new (in /usr/lib/libgdk-x11-2.0.so.0.1000.14) ==14007== by 0x5A0D0AB: (within /usr/lib/libgtk-x11-2.0.so.0.1000.14) But this seams to be only a possible loss <<blocks are possibly lost>> Hope, this can help you ?
FYI, when run under Windows, the program's memory usage increases slowly from ~15 MB to ~20 MB, but more significantly, then after ~20 s, I get the message: (558594.exe:888): Gdk-WARNING **: gdkwindow-win32.c:761: CreateWindowExW failed: The current process has used all of its system allowance of handles for Window Manager objects. And then it crashes. The number of allocated GDI objects grows to ~5000... which indicates that there is definitely some kind of resource leak, and presumably also a related memory leak.
*** Bug 559240 has been marked as a duplicate of this bug. ***
The problem with the test program is that it is so busy creating new widgets that there is never time to free up resources used by those that get unreferenced. If you increase the time_interval to 1000 and decrease the number of entry widgets created in the test_function to 200, it doesn't peg the CPU (at least on my machine) and the resource usage doesn't grow. Do you really need to create tens of thousands of widgets per second in your real application?
my original application creates thousands of widgets, and then idles, and then creates thousands of widgets, and then idles, etc.... It has ample time to free the memory. Unfortunately, my original application takes up more and more memory and becomes slower and slower. I've tried to replicate this behavior as best as I could through this test case.
Well, if I change the time_interval to 15000 (but keep the number of entry widgets at 2000), then on my machine (4-core 2.67 GHz Intel) the test program has (barely) time enough to actually release the resources and memory held by the widgets that are being removed. The CPU time used by the process never really drops to zero, but the memory usage and GDI resource count doesn't keep growing. If I increase the time_interval to 20000, then the process is truly idle for a while between each iteration. (This is on Windows, no idea whether it is more or less efficient in this regards than a local X11 server on Linux, which is what you presumably use.) How long is "ample time" in your real app?
I create/destroy the widgets whenever the user requests a new page; admittedly, sometimes this is less than 15 seconds, but often it is longer than 10 minutes. To be fair, some of the widgets I create are heavier than these text entries, so this might be a factor. From what you're saying I gather that I need to wait until the memory is freed before I ask the computer to free more memory?
is it too much to ask why your application behaves in this way? it seems rather odd, and it is hard to imagine quite what kind of application would need this sort of behaviour.
I'm displaying n-ary trees with text leaves using hboxes, vboxes and labels. The user selects a tree to view and then it gets displayed. He can switch trees whenever he likes. Whenever he switches trees, I destroy all the widgets of the old tree and I create the new widgets for the new tree. Trees can get rather large. The application works great for the first few trees I load, but then bogs down as I load other trees.
is there any way to ask the system if it has finished freeing up the resources? In other words, is there a workaround? It seems that my application doesn't idle as much as I previously thought, so I'd like to make it wait for the resources to be freed, but I have no idea how to do this. And can someone confirm this bug?
if I increase the time interval to 20000 on my laptop, it still doesn't help. my laptop specs: celeron M running at 1.5 Ghz 437 megs of ram this suggests that even if I give the system time to free the memory, it still doesn't help. When I look at gnome-system-monitor, it says "Running" and then switches to "Sleeping" and starts over again.
We're moving to gitlab! As part of this move, we are closing bugs that haven't seen activity in more than 5 years. If this issue is still imporant to you and still relevant with GTK+ 3.22 or master, please consider creating a gitlab issue for it.