Continuing with MP3::Mplib, this morning I've been testing some things more in depth. One one of my concerns was memory usage. One usually doesn't care much about that when writing pure Perl since perl, the interpreter, takes care of freeing memory when necessary (except when it doesn't, but those cases are well known like circular references). XS however is a different pair of shoes.
I had this code in my test script (while keenly watching top's output sorted by memory-usage):
for (0 .. 1000) {
print ".";
MP3::MPlib::set_tag("test_cp.mp3", 2, $tag);
MP3::Mplib::clean_up("test_cp.mp3");
}
<STDIN>;
I was startled to see that perl ate about 19meg of RAM by the time it had reached the <STDIN>
.
So I started cluttering my C code with lots of "free(...);"
, but to no avail at all. I started to get quite frantic since if I weren't able to resolve that the module could never make it to the CPAN.
But finally I found out that not the large structures from the mplib caused the leak, but a quite inocently looking "char *"
value:
void clean_up(filename)
PREINIT:
STRLEN len;
INPUT:
SV * filename; /* <==== LEAK!! */
char * file = SvPV(filename, len);
INIT:
id3_tag_list * taglist;
id3_tag * tag;
int i, j;
PROTOTYPE: $
PPCODE:
taglist = mp_get_tag_list_from_file(file); ...
So all I had to do was adding a "free(file)"
to the end of each of my XSUBS. Now perl finally behaves nicely. I wonder that this is mentioned nowehere in perlguts.pod or perlxs.pod even though it appears to be a common case.