Memory leak on 64bit architecture

However, I replaced line 525

  • free_cache([])
  • gc
  • get_mem

And I was not able to reproduce the problem.

ah, good to know. thanks.

This is due to a bug in booh-classifier; however, that bug doesn’t
explain the whole problem alone…

I’ve made some progress. I have come up with the following C example;
before posting to gnome’s bugzilla, I wanted to ask around if it does
make sense? If you have a few minutes to spare →
http://pastebin.ca/1641693

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <gtk/gtk.h>
#include <dirent.h>

void display_mem() {
char buf[1024];
char *ptr, *ptr2;
ssize_t amount;
int fd = open(“/proc/self/status”, O_RDONLY);
if (fd == -1) {
printf(“cannot open file\n”);
return;
}

amount = read(fd, buf, 1023);
buf[amount] = ‘\0’;
if (!(ptr = strstr(buf, “VmRSS:”))) {
printf(“VmRSS not found in: %s\n”, buf);
close(fd);
return;
}

if (!(ptr2 = strchr(ptr, ‘\n’))) {
printf(“\n not found\n”);
close(fd);
return;
}

*(ptr2+1) = ‘\0’;
printf(ptr);
close(fd);
}

#define count 16

int main(int argc, char** argv) {
GError *error = NULL;
DIR *dir;
struct dirent dp;
int i;
GdkPixbuf
pixbufs[count] = { NULL, };

   gtk_init(&argc, &argv);

   display_mem();

   dir = opendir(".");
   if (dir == NULL) {
           fprintf(stderr, "opendir failed\n");
           abort();
   }

   i = 0;

   while ((dp = readdir (dir)) != NULL) {
           char* file = dp->d_name;
           if (!strstr(file, ".jpg"))
                   continue;
           printf("Load %s\n", file);
           pixbufs[i] = gdk_pixbuf_new_from_file(file, &error);
           if (!pixbufs[i]) {
                   fprintf(stderr, "failure loading %s: %s\n",

file, error->message);
abort();
}
i++;
if (i == count) {
display_mem();
printf(“Unref all but last\n”);
for ( i = 0; i < count - 1; i++ )
g_object_unref(pixbufs[i]);
display_mem();
// last one becomes first in array
pixbufs[0] = pixbufs[count - 1];
i = 1;
}
}

   closedir (dir);

   return 0;

}

/*
That tries to mimic the allocation/deallocation in a ruby-gnome2 program
showing
the jpg images in current directory; the mark&sweep GC of ruby won’t
allow for
all GdkPixbufs to be unref’ed immediately after being not used
anymore, but instead
they are unref’ed grouped, all but last one because we want to keep the
last
pixbuf around for the program.

Result (against 2.18.3) on x86_64 architecture:

VmRSS: 5768 kB
Load img_0290.jpg
Load 1.jpg
Load 2.jpg
Load 3.jpg
Load 4.jpg
Load 10.jpg
Load 11.jpg
Load 12.jpg
Load 13.jpg
Load 14.jpg
Load 15.jpg
Load 16.jpg
Load 17.jpg
Load 18.jpg
Load 19.jpg
Load 20.jpg
VmRSS: 380968 kB
Unref all but last
VmRSS: 29788 kB
Load 21.jpg
Load 22.jpg
Load 23.jpg
Load 24.jpg
Load 25.jpg
Load 26.jpg
Load 27.jpg
Load 28.jpg
Load 29.jpg
Load 30.jpg
Load 31.jpg
Load 32.jpg
Load 33.jpg
Load 34.jpg
Load 35.jpg
VmRSS: 380920 kB
Unref all but last
VmRSS: 357508 kB
Load 36.jpg
Load 37.jpg
Load 38.jpg
Load 39.jpg
Load 40.jpg
Load 41.jpg
Load 42.jpg
Load 43.jpg
Load 44.jpg
Load 45.jpg
Load 46.jpg
Load 47.jpg
Load 48.jpg
Load 49.jpg
Load t.jpg
VmRSS: 380916 kB
Unref all but last
VmRSS: 380916 kB
Load t2.jpg
Load t3.jpg
Load 100.jpg

Notice that after a few iterations, even after unref’ing all pixbufs
but the last one, the RSS of the
program is very high. Contrast with the same program on i686
architecture (with the same data):

VmRSS: 4872 kB
Load img_0290.jpg
Load 1.jpg
Load 2.jpg
Load 3.jpg
Load 4.jpg
Load 10.jpg
Load 11.jpg
Load 12.jpg
Load 13.jpg
Load 14.jpg
Load 15.jpg
Load 16.jpg
Load 17.jpg
Load 18.jpg
Load 19.jpg
Load 20.jpg
VmRSS: 380048 kB
Unref all but last
VmRSS: 28868 kB
Load 21.jpg
Load 22.jpg
Load 23.jpg
Load 24.jpg
Load 25.jpg
Load 26.jpg
Load 27.jpg
Load 28.jpg
Load 29.jpg
Load 30.jpg
Load 31.jpg
Load 32.jpg
Load 33.jpg
Load 34.jpg
Load 35.jpg
VmRSS: 380048 kB
Unref all but last
VmRSS: 28868 kB
Load 36.jpg
Load 37.jpg
Load 38.jpg
Load 39.jpg
Load 40.jpg
Load 41.jpg
Load 42.jpg
Load 43.jpg
Load 44.jpg
Load 45.jpg
Load 46.jpg
Load 47.jpg
Load 48.jpg
Load 49.jpg
Load t.jpg
VmRSS: 380048 kB
Unref all but last
VmRSS: 28868 kB
Load t2.jpg
Load t3.jpg
Load 100.jpg

On i686, the memory seems to be properly reclaimed, not on x86_64…

*/


Guillaume C. - http://zarb.org/~gc/


Guillaume C. - http://zarb.org/~gc/

2009/10/24 Guillaume C. [email protected]

I’ve made some progress. I have come up with the following C example;
before posting to gnome’s bugzilla, I wanted to ask around if it does
make sense? If you have a few minutes to spare →
http://pastebin.ca/1641693

With the foloowing patch, it does not leak anymore on my debian sid 64.

— test-unref-orig.c 2009-10-26 14:09:28.550389546 +0100
+++ test-unref.c 2009-10-26 14:10:07.627736671 +0100
@@ -42,8 +42,10 @@
GError *error = NULL;
DIR *dir;
struct dirent *dp;

  •   int i;
    
  •   int i,j;
    
  •   int last = count - 1;
      GdkPixbuf* pixbufs[count] = { NULL, };
    
  •   char* file;
    
      gtk_init(&argc, &argv);
    

@@ -58,10 +60,10 @@
i = 0;

    while ((dp = readdir (dir)) != NULL) {
  •           char* file = dp->d_name;
    
  •           if (!strstr(file, ".jpg"))
    
  •           file = dp->d_name;
    
  •           if (!(strstr(file, ".jpg")||strstr(file, ".JPG")))
                      continue;
    
  •           printf("Load %s\n", file);
    
  •           // printf("Load %s\n", file);
              pixbufs[i] = gdk_pixbuf_new_from_file(file, &error);
              if (!pixbufs[i]) {
                      fprintf(stderr, "failure loading %s: %s\n",
    

@@ -70,13 +72,17 @@
}
i++;
if (i == count) {

  •                   printf("\nBefore unref\n");
                      display_mem();
                      printf("Unref all but last\n");
    
  •                   for ( i = 0; i < count - 1; i++ )
    
  •                           g_object_unref(pixbufs[i]);
    
  •                   for ( j = 0; j < last; j++ )
    
  •                           g_object_unref(pixbufs[j]);
                      display_mem();
                      // last one becomes first in array
    
  •                   pixbufs[0] = pixbufs[count - 1];
    
  •                   pixbufs[0] = gdk_pixbuf_copy(pixbufs[last]);
    
  •                   g_object_unref(pixbufs[last]);
    
  •                   printf("After putting last in first place\n");
    
  •                   display_mem();
                      i = 1;
              }
      }
    

Apart from the cosmetic changes, the main difference is I copy the
pifbux
from last to first, instead of copying the pointer.

I tried a lot of variants, and I suspect “gdk_pixbuf_new_from_file” is
keeping some ref around until you clear all ref opened from the
function.
However my C skill are mostly inexistent, so it may well be something
else.

On i686, the memory seems to be properly reclaimed, not on x86_64…

I don’t have a 32 bits system to test on right now, but I do see the
problem
on x86_64.

Looks like a bug in GDK to me.

regards

Simon A.