Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

クロージャの解放

gist落ちてるのでここにメモ。

package DONE1;
sub DESTROY{ warn 'd1:', shift; }

package DONE2;
sub DESTROY{ warn 'd2:', shift; }

package DONE3;
sub DESTROY{ warn 'd3:', shift; }

package DONE4;
sub DESTROY{ warn 'd4:', shift; }

package DONE5;
sub DESTROY{ warn 'd5:', shift; }


package main;
use strict;
use warnings;
use Scalar::Util;

my ($inner, $outer);
{
  my $d1 = bless {}, 'DONE1';
  my $d2 = bless {}, 'DONE2';
  bless sub {my $d1; my $d2; }, 'DONE3';
  ( $outer = bless sub { 
    $d1; $inner = bless sub { $d2; }, 'DONE4'; 
  }, 'DONE5' )->();
}

warn "free outer";
Scalar::Util::weaken $outer;
warn "free inner";
Scalar::Util::weaken $inner;
warn "free end";
__END__
[v5.8.8]
free outer at - line 32.
free inner at - line 34.
d4:DONE4=CODE(0x82427c) at - line 11.
d5:DONE5=CODE(0x800eac) at - line 14.
d1:DONE1=HASH(0x800d80) at - line 2.
free end at - line 36.
d2:DONE2=HASH(0x800e34) at - line 5 during global destruction.

[v5.10.0]
free outer at - line 32.
free inner at - line 34.
d4:DONE4=CODE(0x1555338) at - line 11.
d5:DONE5=CODE(0x14fc448) at - line 14.
d2:DONE2=HASH(0x15554a0) at - line 5.
d1:DONE1=HASH(0x14d7df0) at - line 2.
free end at - line 36.

-外の変数を使わないとクロージャとならない(DONE3は解放されない)
-クロージャは内側から順に解放される($outerは$innerが消えるまで残る)。
-Perl 5.8系では、2つ外の参照を解放できない($d2はリーク)

AnyEvent使っててクロージャ絡みのリークがよくわからんかったので(とても原始的に)検証しただけのメモです。