从一个匿名子节点递归地调用另一个匿名子节点是否安全?



我想使用匿名子组件而不是命名子组件的原因是我想在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);

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

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

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

我唯一能想到的是子程序永远不会被释放,即使$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'

第一个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'

可以这样写:

sub first {
    my $val = shift;
    print "val: $val";
    second($val);
}
sub second {
    my $val = shift;
    if (0 < $val) {
        $val = $val - 1;
        first($val);
    }
}
first(10);

唯一需要注意的是,如果subs有一个原型,或者如果你想省略subs参数周围的父元素,你需要声明subs。

sub first($);
sub second($);
sub first($) {
    my $val = shift;
    print "val: $val";
    second $val;
}
sub second($) {
    my $val = shift;
    if (0 < $val) {
        $val = $val - 1;
        first $val;
    }
}
first 10;
另一方面,你的版本有内存泄漏。第一个子节点捕获对第二个子节点的引用,第二个子节点捕获对第一个子节点的引用。
$ perl -e'
   sub DESTROY { print "Destroyedn" }
   {
      my ($first, $second);
      $first = sub { $second };
      $second = sub { $first };
      bless($first);
   }
   print("Subs should have been destroyed by nown");
'
Subs should have been destroyed by now
Destroyed

解决方案取决于您最初决定使用匿名子节点的原因

相关内容

  • 没有找到相关文章

最新更新