Has anyone tried throwing DTrace at this problem?  I don't have any
Solaris access here at RubyConf, and I don't use FCGI, or I'd give it
a go.

On 10/15/05, Yohanes Santoso <ysantoso-rubytalk / dessyku.is-a-geek.org> wrote:
> Eric Mahurin <eric_mahurin / yahoo.com> writes:
>
> > n=2**13;(1..n).each{|i|
> > a=(1..i).to_a;self.class.send(:define_method,:"f#{i}"){i*i}};GC.start;
> > IO.readlines("/proc/#{Process.pid}/status").grep(/VmSize/).display'
> > VmSize:   172028 kB
>
> > ruby -e '
> > n=2**13;(1..n).each{|i|
> > a=(1..i).to_a;self.class.send(:define_method,:"f#{i}"){i*i};a=nil};GC.start;
> > IO.readlines("/proc/#{Process.pid}/status").grep(/VmSize/).display'
> > VmSize:    11504 kB
>
> Stop right there. I want to remind people that you can't use VmSize as
> a leak indicator. In some OS, VmSize is an always increasing
> number. Memory allocated in a process is not returned to the OS until
> the process dies.
>
> Here is a C program that free() every malloc(), yet still have
> outrageous VmSize;
>
> ysantoso@jenny:/tmp$ gcc -W -Wall ./leak.c -o leak && ./leak immed && ./leak not_immed
> Freeing immediately
> ----BEFORE----
> malloc count = 0
> free count   = 0
> VmSize:     1572 kB
> VmLck:         0 kB
> VmRSS:       364 kB
> VmData:      156 kB
> VmStk:        88 kB
> VmExe:         4 kB
> VmLib:      1280 kB
> VmPTE:        16 kB
> Executing leak test
> unwinding
> ----AFTER-----
> malloc count = 8193
> free count   = 8193
> VmSize:     1572 kB
> VmLck:         0 kB
> VmRSS:       440 kB
> VmData:      156 kB
> VmStk:        88 kB
> VmExe:         4 kB
> VmLib:      1280 kB
> VmPTE:        16 kB
> Not freeing immediately
> ----BEFORE----
> malloc count = 0
> free count   = 0
> VmSize:     1568 kB
> VmLck:         0 kB
> VmRSS:       364 kB
> VmData:      156 kB
> VmStk:        84 kB
> VmExe:         4 kB
> VmLib:      1280 kB
> VmPTE:        16 kB
> Executing leak test
> unwinding
> freeing 8192 elements
> ----AFTER-----
> malloc count = 8193
> free count   = 8192
> VmSize:   206360 kB
> VmLck:         0 kB
> VmRSS:    205280 kB
> VmData:   204948 kB
> VmStk:        84 kB
> VmExe:         4 kB
> VmLib:      1280 kB
> VmPTE:       216 kB
> ysantoso@jenny:/tmp$ cat ./leak.c
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> int malloc_count = 0;
> int free_count = 0;
>
> void *
> counting_malloc(size_t size)
> {
>   malloc_count++;
>   return malloc(size);
> }
>
> void
> counting_free(void *ptr)
> {
>   free_count++;
>   if (ptr == NULL) {
>     fprintf(stderr, "Warning: free-ing NULL pointer\n");
>   }
>   free(ptr);
> }
>
> void
> display_vminfo()
> {
>   FILE *status = fopen("/proc/self/status", "r");
>   char line[132];
>   while (fgets(line, 132, status)) {
>     if (strstr(line, "Vm") == line) {
>       printf(line);
>     }
>   }
>   fclose(status);
> }
>
> /* allocs about 200M of mem. if free_immed_p, then memory allocated is free()ed immediately */
> void
> leak_test(int free_immed_p)
> {
>   int i, j;
>   char **array = NULL;
>   int max_array_idx = -1;
>   int max_array_size = 8192;
>   int element_size = 25*1024;
>   array = counting_malloc(max_array_size * sizeof(char*));
>   if (!array) {
>     fprintf(stderr, "Unable to malloc\n");
>     goto die;
>   }
>   for (i=0; i < max_array_size; i++) {
>     char *element = counting_malloc(element_size);
>     if (!element) {
>       fprintf(stderr, "Unable to malloc\n");
>       goto die;
>     }
>     /* walk through the allocated mem to negate any lazy allocation schema */
>     for (j=0; j < element_size; j++) {
>       element[j] = '\0';
>     }
>     array[i] = element;
>     max_array_idx = i;
>     if (free_immed_p) {
>       counting_free(element);
>     }
>   }
>  die:
>   fprintf(stderr, "unwinding\n");
>   if (array) {
>     if (!free_immed_p) {
>       fprintf(stderr, "freeing %d elements\n", max_array_idx + 1);
>       for (i=0; i < max_array_idx; i++) {
>         counting_free(array[i]);
>       }
>     }
>     counting_free(array);
>   }
> }
>
>
>
> void
> usage()
> {
>   fprintf(stderr, "Don't understand argument. immed or not_immed\n");
> }
>
> int
> main(int argc, char **argv)
> {
>   int free_immed_p;
>   if (argc != 2) {
>     usage();
>     return 1;
>   }
>   if (strcmp("immed", argv[1]) == 0) {
>     printf("Freeing immediately\n");
>     free_immed_p = 1;
>   } else if (strcmp("not_immed", argv[1]) == 0) {
>     printf("Not freeing immediately\n");
>     free_immed_p = 0;
>   } else {
>     usage();
>     return 1;
>   }
>   printf("----BEFORE----\n");
>   printf("malloc count = %d\n", malloc_count);
>   printf("free count   = %d\n", free_count);
>   display_vminfo();
>   printf("Executing leak test\n");
>   leak_test(free_immed_p);
>   printf("----AFTER-----\n");
>   printf("malloc count = %d\n", malloc_count);
>   printf("free count   = %d\n", free_count);
>   display_vminfo();
>   return 0;
> }
>
>
>
> > Here is the fixed version:
>
> You can't say this if you only have VmSize.
>
>
> YS.
>
>