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 558594 - memory leak when destroying many widgets
memory leak when destroying many widgets
Status: RESOLVED OBSOLETE
Product: gtk+
Classification: Platform
Component: .General
2.1.x
Other All
: Normal critical
: ---
Assigned To: gtk-bugs
gtk-bugs
: 559240 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2008-10-30 20:58 UTC by Jacques Le Normand
Modified: 2018-02-10 04:39 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
valgrind output (75.31 KB, text/plain)
2008-10-30 22:33 UTC, Jacques Le Normand
Details

Description Jacques Le Normand 2008-10-30 20:58:37 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
Comment 1 Christian Persch 2008-10-30 22:19:20 UTC
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.
Comment 2 Jacques Le Normand 2008-10-30 22:33:05 UTC
Created attachment 121697 [details]
valgrind output
Comment 3 Jacques Le Normand 2008-10-30 22:33:49 UTC
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.
Comment 4 Christian Persch 2008-10-30 23:03:53 UTC
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.)


Comment 5 Jacques Le Normand 2008-10-30 23:32:59 UTC
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
Comment 6 Jacques Le Normand 2008-10-31 01:19:27 UTC
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
Comment 7 thelema 2008-10-31 03:33:19 UTC
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

Comment 8 Benjamin Berg 2008-10-31 10:13:02 UTC
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?
Comment 9 thelema 2008-10-31 12:41:23 UTC
@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.
Comment 10 Jacques Le Normand 2008-10-31 18:34:22 UTC
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 ?
Comment 11 Tor Lillqvist 2008-11-04 09:36:46 UTC
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.
Comment 12 Tor Lillqvist 2008-11-04 09:40:01 UTC
*** Bug 559240 has been marked as a duplicate of this bug. ***
Comment 13 Tor Lillqvist 2008-11-04 10:06:03 UTC
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?
Comment 14 Jacques Le Normand 2008-11-04 18:48:41 UTC
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. 

Comment 15 Tor Lillqvist 2008-11-04 19:17:17 UTC
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?
Comment 16 Jacques Le Normand 2008-11-04 19:30:20 UTC
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?
Comment 17 Paul Davis 2008-11-04 20:32:46 UTC
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.
Comment 18 Jacques Le Normand 2008-11-04 21:09:24 UTC
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.
Comment 19 Jacques Le Normand 2009-02-08 06:13:29 UTC
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?

Comment 20 Jacques Le Normand 2009-02-10 05:41:35 UTC
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.

Comment 21 Matthias Clasen 2018-02-10 04:39:58 UTC
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.