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
