Subject: | Memory leak in Plugin::Filter |
Hi. I found a memory leak and reported. I used following simple script
to find the problem.
use strict;
use warnings;
use Template;
for my $l (1 .. 1000) {
my $tpl = Template->new(PLUGIN_BASE => 'test');
$tpl->context->plugin('simple', []);
warn `ps -o rss= -p $$` if $l % 10 == 0;
}
I read https://rt.cpan.org/Public/Bug/Display.html?id=46691 and
understood my patch had been reverted.
So I wrote another one. How is this patch? All tests in the t/ directory
are passed and there are no memory leaks.
Since I thought only the context should have the filter's reference, I
weakened another references.
Subject: | for_tt-2.22.patch |
diff --git a/lib/Template/Plugin/Filter.pm b/lib/Template/Plugin/Filter.pm
index 420cc94..bb3de9d 100644
--- a/lib/Template/Plugin/Filter.pm
+++ b/lib/Template/Plugin/Filter.pm
@@ -48,6 +48,7 @@ sub new {
_ARGS => \@args,
_CONFIG => $config,
}, $class;
+ weaken($self->{_CONTEXT});
return $self->init($config)
|| $class->error($self->error());
@@ -62,31 +63,29 @@ sub init {
sub factory {
my $self = shift;
- my $this = $self;
-
- # This causes problems: https://rt.cpan.org/Ticket/Display.html?id=46691
- # If the plugin is loaded twice in different templates (one INCLUDEd into
- # another) then the filter gets garbage collected when the inner template
- # ends (at least, I think that's what's happening). So I'm going to take
- # the "suck it and see" approach, comment it out, and wait for someone to
- # complain that this module is leaking memory.
-
- # weaken($this);
if ($self->{ _DYNAMIC }) {
- return $self->{ _DYNAMIC_FILTER } ||= [ sub {
+ return $self->{ _DYNAMIC_FILTER } if $self->{ _DYNAMIC_FILTER };
+
+ my $dynamic_filter = [ sub {
my ($context, @args) = @_;
my $config = ref $args[-1] eq 'HASH' ? pop(@args) : { };
return sub {
- $this->filter(shift, \@args, $config);
+ $self->filter(shift, \@args, $config);
};
}, 1 ];
+ weaken($self->{ _DYNAMIC_FILTER } = $dynamic_filter);
+ return $dynamic_filter;
}
else {
- return $self->{ _STATIC_FILTER } ||= sub {
- $this->filter(shift);
+ return $self->{ _STATIC_FILTER } if $self->{ _STATIC_FILTER };
+
+ my $static_filter = sub {
+ $self->filter(shift);
};
+ weaken($self->{ _STATIC_FILTER } = $static_filter);
+ return $static_filter;
}
}