I have this example with nested closures which demonstrates memory leak
use v5.10;
use strict;
package Awesome;
sub new {
bless {steps => [], surprise => undef}, shift;
}
sub say {
print "awesome: ", $_[1], "\n";
}
sub prepare {
my ($self, @steps) = @_;
for my $s (@steps) {
push @{$self->{steps}}, sub {
$self->say($s);
if ($s eq 'pony') {
$self->{surprise} = sub {
$s;
}
}
};
}
}
sub make {
my $self = shift;
while (my $step = shift @{$self->{steps}}) {
$step->();
}
if ($self->{surprise}) {
printf("And you have surprise: %s\n", $self->{surprise}->());
}
}
sub DESTROY {
warn "destroying";
}
package main;
my $a = Awesome->new;
$a->prepare('barbie','pony','flash');
$a->make();
Output on my perl is
awesome: barbie
awesome: pony
awesome: flash
And you have surprise: pony
destroying at /tmp/t.pl line 43 during global destruction.
And this "during global destruction" means that object couldn't be destroyed in normal way, because it has some circular references.
However the only circular references are created by
push @{$self->{steps}}, sub {
$self->say($s);
where we are using $self inside first closure. And later inside make() we'll delete this steps and circular references. But looks like this nested closure with "suprise" makes problems. For example if we'll not pass "pony" to prepare() output will be good as expected:
awesome: barbie
awesome: flash
destroying at /tmp/t.pl line 43.
So, is nested closures in perl captures the same variables as closure from upper level already captured even if we are not using them?
Perl used to over-capture in nested closures before, but it does not do so since 5.18.
$ tail -n 9 a.pl # Modified to make clearer when the object is destroyed.
package main;
{
my $a = Awesome->new;
$a->prepare('barbie','pony','flash');
$a->make();
}
print "done.\n";
$ 5.16.3t/bin/perl a.pl
awesome: barbie
awesome: pony
awesome: flash
And you have surprise: pony
done.
destroying at a.pl line 43 during global destruction.
$ 5.18.2t/bin/perl a.pl
awesome: barbie
awesome: pony
awesome: flash
And you have surprise: pony
destroying at a.pl line 43.
done.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With