Subject: | Memory leak on XML::Generator-0.93 (included) |
Module: XML::Geenrator-0.93
perl: v5.8.0
uname output: Linux, 2.4.20-4GB, i686, GNU/Linux
Creating an XML::Generator object with XML::Generator->new generates a memory leak: The "new" method places a reference to a subroutine in the %tag_factory hash, the subroutine contains a reference to the corresponding object. Objects that are no longer used will never go out of scope.
Supplied is a patch to the XML::Generator module (v 0.93) which fixes this plus a test script for the t/ directory, which is repeated below [ ps: please contact me if the server doesn't accept patch file and I'll email it ].
#!/usr/bin/perl -w
use strict;
use XML::Generator;
# assumes presence of a /proc filesystem
# and that the file /proc/<process id>/statm
# contains the memory useage information
print "1..1\n";
sub printmem
{
my $text = shift;
local *FILE;
open FILE, "</proc/$$/statm";
my $line = <FILE>;
close FILE;
chomp $line;
my @figures = map { $_ * 4 } split /\s+/, $line;
print "$text $figures[0]\n";
return $figures[0];
}
print "# memory use with XML::Generator->new call inside loop\n";
my %a = map {$_,1} qw ( 1 10 100 1000 10000 );
my %mem = %a;
foreach my $i ( 1 .. 10000 )
{
my $x = new XML::Generator( 'escape' => 'always',
'conformance' => 'strict' );
my $s = $x->xml( $x->a( $x->b ));
$a{$i} and $mem{$i} = &printmem( "# Program size after $i iterations : " );
}
print $mem{1000} eq $mem{10000} ?
"ok 1 # memory stays at around $mem{1000}kB\n" :
"not ok 1 # memory grown from $mem{100}kB => $mem{10000}kB after 10,000 iterations\n";
#
# TODO: make test more fuzzy?
#
diff -N -r -u XML-Generator-0.93/Generator.pm XML-Generator-0.93-patched/Generator.pm
--- XML-Generator-0.93/Generator.pm 2003-01-22 15:41:05.000000000 +0000
+++ XML-Generator-0.93-patched/Generator.pm 2003-11-28 02:40:42.000000000 +0000
@@ -271,6 +271,7 @@
my ($tag) = $AUTOLOAD =~ /.*::(.*)/;
unshift @_, $tag;
+ unshift @_, $this;
goto &{ $tag_factory{$this} };
}
@@ -459,6 +460,7 @@
return XML::Generator::cdata->new([$xml]);
}
+=pod
=head2 xml
"Final" XML document. Must be called with one and exactly one
@@ -657,21 +659,30 @@
# the tag.
sub tag {
- my $sub = XML::Generator::util::c_tag(shift);
+ my $sub = XML::Generator::util::c_tag($_[0]);
goto &{ $sub } if $sub;
}
# Generate a closure that encapsulates all the behavior to generate a tag
sub c_tag {
- my $this = shift;
+ my $arg = shift;
+
+ my $strict = $arg->{'conformance'} eq 'strict';
+ $arg->{'always'} = (my $escape = $arg->{'escape'}) & XML::Generator::ESCAPE_ALWAYS;
+ $arg->{'high_bit'} = $escape & XML::Generator::ESCAPE_HIGH_BIT;
+ my $empty = $arg->{'empty'};
+ my $pretty = $arg->{'pretty'};
+ undef $arg;
+ return sub {
+
+ my $this = shift;
my $strict = $this->{'conformance'} eq 'strict';
- my $always = (my $escape = $this->{'escape'}) & XML::Generator::ESCAPE_ALWAYS;
- my $high_bit = $escape & XML::Generator::ESCAPE_HIGH_BIT;
+ my $always = $this->{'always'};
+ my $high_bit = $this->{'high_bit'} ;
my $empty = $this->{'empty'};
my $pretty = $this->{'pretty'};
- return sub {
my $tag = shift || return undef; # catch for bad usage
# parse our argument list to check for hashref/arrayref properties
diff -N -r -u XML-Generator-0.93/t/Generator_memoryleak.t XML-Generator-0.93-patched/t/Generator_memoryleak.t
--- XML-Generator-0.93/t/Generator_memoryleak.t 1970-01-01 01:00:00.000000000 +0100
+++ XML-Generator-0.93-patched/t/Generator_memoryleak.t 2003-11-28 02:34:53.000000000 +0000
@@ -0,0 +1,53 @@
+#!/usr/bin/perl -w
+
+use strict;
+use XML::Generator;
+
+# assumes presence of a /proc filesystem
+# and that the file /proc/<process id>/statm
+# contains the memory useage information
+
+sub exit_txt
+{
+ print "$_[0]\n";
+ exit;
+}
+
+print "1..1\n";
+-d "/proc" or &exit_txt( "ok 1 \# skip Filesystem /proc does not seem to exist on this OS" );
+-d "/proc/$$" or &exit_txt( "not ok 1 \# todo /proc filesystem seems to exist, but cannot /proc/<process id> directory in filesystem" );
+-f "/proc/$$/statm" or &exit_txt( "ok 1 \# skip /proc filesystem seems to exists but /proc/<process id>/statm memory status file does not seem to exist" );
+
+
+sub printmem
+{
+ my $text = shift;
+ local *FILE;
+ open FILE, "</proc/$$/statm";
+ my $line = <FILE>;
+ close FILE;
+ chomp $line;
+ my @figures = map { $_ * 4 } split /\s+/, $line;
+ print "$text $figures[0]\n";
+ return $figures[0];
+}
+
+print "# memory use with XML::Generator->new call inside loop\n";
+
+my %a = map {$_,1} qw ( 1 10 100 1000 10000 );
+my %mem = %a;
+foreach my $i ( 1 .. 10000 )
+{
+ my $x = new XML::Generator( 'escape' => 'always',
+ 'conformance' => 'strict' );
+ my $s = $x->xml( $x->a( $x->b ));
+ $a{$i} and $mem{$i} = &printmem( "# Program size after $i iterations : " );
+}
+
+print $mem{1000} eq $mem{10000} ?
+ "ok 1 # memory stays at around $mem{1000}kB\n" :
+ "not ok 1 # memory grown from $mem{100}kB => $mem{10000}kB after 10,000 iterations\n";
+
+#
+# TODO: make test more fuzzy?
+#