From: Mike S. <m...@pe...> - 2004-06-13 07:14:28
|
Kevin Goess wrote on 6/8/2004, 1:00 AM: > So I'm pretty sure it's the closure that's the problem. With the > "return sub{}" change in generate_coderef(), putting a while loop around > the above code and running it forever doesn't use up any memory. Great detective work, thanks, Kevin! With your analysis, I was able to reduce it to this simple case: package Foo; sub new { bless {} } sub DESTROY { warn "Destroying Foo"; } sub coderef { my $bar = Bar->new(); my $cref; eval "\$cref = sub { \$bar };"; return $cref; } package Bar; sub new { bless {} } sub DESTROY { warn "Destroying Bar"; } package main; my $foo = Foo->new(); $foo->{bar} = $foo->coderef(); This shows: Destroying Foo at ml line 4. Destroying Bar at ml line 13 during global destruction. If you change the code slightly to package Foo; sub new { bless {} } sub DESTROY { warn "Destroying Foo"; } sub coderef { my $bar = Bar->new(); my $cref; $cref = eval "sub { \$bar };"; return $cref; } package Bar; sub new { bless {} } sub DESTROY { warn "Destroying Bar"; } package main; my $foo = Foo->new(); $foo->{bar} = $foo->coderef(); which pulls the assignment out of the "eval", then you'll get Destroying Foo at ml line 4. Destroying Bar at ml line 13. And, alas, if we apply the following patch to Log4perl, the leak's gone, yay :) Index: lib/Log/Log4perl/Logger.pm =================================================================== RCS file: /cvsroot/log4perl/Log-Log4perl/lib/Log/Log4perl/Logger.pm,v retrieving revision 1.61 diff -a -u -r1.61 Logger.pm --- lib/Log/Log4perl/Logger.pm 6 Jun 2004 19:47:29 -0000 1.61 +++ lib/Log/Log4perl/Logger.pm 13 Jun 2004 07:00:34 -0000 @@ -233,7 +233,7 @@ } my $code = <<EOL; - \$coderef = sub { + sub { my (\$logger) = shift; my (\$level) = pop; my \$message; @@ -288,7 +288,7 @@ EOL - eval $code or die "$@"; + $coderef = eval $code or die "$@"; return $coderef; } Now the $1,000,000 question ... who can explain this? :) -- -- Mike Mike Schilli m...@pe... |