从另一个中递归调用一个匿名sub是否安全?

Yak*_*kov 5 perl mason

我想使用匿名子而不是命名子的原因是因为我想在Mason子组件中定义这些子组件(http://www.masonbook.com/book/chapter-2.mhtml#TOC-ANCHOR-7),与命名的潜艇表现不佳.

例如,如果我以这种方式编写代码:

my ($first, $second);
$first = sub {
    my $val = shift;
    print "val: $val";
    $second->($val);
};
$second = sub {
    my $val = shift;
    if (0 < $val) {
        $val = $val - 1;
        $first->($val);
    }
};
$first->(10);
Run Code Online (Sandbox Code Playgroud)

这种方法中是否存在任何隐藏的陷阱(例如内存泄漏等)?

正如@Schwern所解释的那样,Perl不会释放这些子的内存,因为它们之间存在循环引用.

但更具体地说,内存分配是否会线性增长,因为$ val会增加,或者它不依赖于调用堆栈深度?因为我可以将这些子元素放在mason <%once>块中,在这种情况下,这些子函数只会被初始化一次.

Sch*_*ern 5

唯一一个我能想到的是,子程序将永远不会被释放,即使$first$second走出去的范围.$first代码是指$second,$second代码指的是$first.这是一个循环数据结构,Perl的内存分配无法解除分配.

$ perl -wlE 'for (1..10_000) { my($first, $second); $first = sub {};  $second = sub {} } say "Done"; sleep 1000'

$ perl -wlE 'for (1..10_000) { my($first, $second); $first = sub { $second->() }; $second = sub { $first->() } } say "Done"; sleep 1000'
Run Code Online (Sandbox Code Playgroud)

第一个Perl进程在循环后使用1912K,第二个使用10320K.无论创建多少CV,第一个都不会增长,第二个会.

要解决这个问题,你必须通过取消定义$first或打破这个圈子$second.第三个调用undef $first循环内部,其内存不会增长.

$ perl -wlE 'for (1..100_000) { my($first, $second); $first = sub { $second->() }; $second = sub { $first->() }; undef $first; } say "Done"; sleep 1000'
Run Code Online (Sandbox Code Playgroud)