# Memory leak on 64bit architecture

**URL:** <https://www.ruby-forum.com/t/memory-leak-on-64bit-architecture/177826>\
**Category:** Ruby-Gnome 2\
**Created:** [October 24, 2009, 7:00pm UTC](https://www.ruby-forum.com/t/memory-leak-on-64bit-architecture/177826 "2009-10-24T19:00:24Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![blueprint](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/cc9497/32.png) [@blueprint](https://www.ruby-forum.com/u/blueprint)\
**Post date:** [October 24, 2009, 7:00pm UTC](https://www.ruby-forum.com/t/memory-leak-on-64bit-architecture/177826/1 "2009-10-24T19:00:24Z")

</div>

> > 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](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/](http://zarb.org/~gc/)

–  
Guillaume C. - [http://zarb.org/~gc/](http://zarb.org/~gc/)

---

<div class="post-metadata">

**Author:** ![blueprint](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/cc9497/32.png) [@blueprint](https://www.ruby-forum.com/u/blueprint)\
**Post date:** [October 26, 2009, 2:17pm UTC](https://www.ruby-forum.com/t/memory-leak-on-64bit-architecture/177826/2 "2009-10-26T14:17:45Z")

</div>

2009/10/24 Guillaume C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> 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](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.
