Hi,

I have a memory leak problem in some XS code that populates a (passed in) hash with (newly created) hash references.

Here is a sample XS routine and Perl wrapper which reproduces the problem:

# XS
void
_fooxs(href)
   INPUT:
       HV *href;

   PREINIT:
       int i;
       int keylen;
       char key[6];
       HV *hash;

PROTOTYPE: $

   CODE:
       for (i = 0; i < 100; i++) {
           hash = newHV();
           hv_store(hash, "string", 6, newSVpv("one", 3), 0);
           hv_store(hash, "number", 6, newSViv(1), 0);
           keylen = sprintf(key, "key%02d", i);
           hv_store(href, (const char *) key, keylen,
               newRV_noinc((SV *) hash), 0);
       }

   OUTPUT:
       href

# Perl
sub fooxs() {
   my $href = {};
   _fooxs($href);
   return $href;
}

A simple test program that calls fooxs() 5000 times reaches about 100MB by the time it is complete!

A similar test program that calls foopl(), the pure-Perl function below that does the same thing, only reaches about 2MB.

# Pure Perl
sub foopl() {
   my $href = {};
   for (my $i = 0; $i < 100; $i++) {
       my %hash = ();
       $hash{string} = 'one';
       $hash{number} = 1;
       my $key = sprintf "key%02d", $i;
       $href->{$key} = \%hash;
   }
   return $href;
}

What have I done wrong in the XS?

I assume it is something to do with ref counts or "mortalness", but I can't see where. The functions newHV(), newSVpv() and newSViv() all set the ref count to 1, and I used the "_noinc" version of newRV when I stored a reference to the newly created hash inside the passed in hash. What am I missing?

Thanks in advance,

Steve




Reply via email to