Perl 从一个匿名子系统递归调用另一个匿名子系统安全吗?
我之所以想使用匿名子组件而不是命名子组件,是因为我想在Mason subcomponents()中定义这些子组件,而Mason subcomponents()在命名子组件中表现不佳 例如,如果我以这种方式编写代码:Perl 从一个匿名子系统递归调用另一个匿名子系统安全吗?,perl,mason,Perl,Mason,我之所以想使用匿名子组件而不是命名子组件,是因为我想在Mason subcomponents()中定义这些子组件,而Mason subcomponents()在命名子组件中表现不佳 例如,如果我以这种方式编写代码: my ($first, $second); $first = sub { my $val = shift; print "val: $val"; $second->($val); }; $second = sub { my $val = shif
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);
my($first,$second);
$first=sub{
我的$val=班次;
打印“val:$val”;
$second->($val);
};
$second=sub{
我的$val=班次;
如果(0<$val){
$val=$val-1;
$first->($val);
}
};
$first->(10);
这种方法是否存在任何隐藏的漏洞(例如内存泄漏等)
正如@Schwern所解释的,Perl不会释放这些sub的内存,因为它们之间有一个循环引用
但更具体地说,内存分配会随着$val的增加而线性增长,还是不依赖于调用堆栈深度?因为我可以将这些sub放在mason块中,在这种情况下,这些sub将只初始化一次。以下情况就可以了:
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);
解决方案取决于您决定首先使用anon subs的原因。我唯一能想到的是,即使
$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,第一个CV都不会增长,第二个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'
谢谢大家!但基本上,如果我在循环之外定义匿名子循环,我的内存占用不会增加?循环只会夸大问题;您仍然必须取消定义$first或$second函数以避免循环结构。@Yakov循环仅用于说明泄漏。它A)提供了一个词法上下文(即块),子例程在退出时会被破坏;B)夸大了内存泄漏,因此它会出现在一个粗糙的工具中,如
ps
@Yakov,如果代码不在某种循环中,那么很难想象为什么需要一个子例程。同样的道理,如果需要anon潜艇,那么Schwern释放它们的解决方案可能无法使用。
$ 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 -wlE 'for (1..100_000) { my($first, $second); $first = sub { $second->() }; $second = sub { $first->() }; undef $first; } say "Done"; sleep 1000'