我知道perl无法检测到递归引用:
$a = \$a;
在这种情况下, $a
永远不会被GC。
怎么样:
@a = ({1,2,3}, [1,2,3]);
当{1,2,3}
超出范围时,是否会收集匿名[1,2,3]
和@a
?
如何证明是或否?
答案 0 :(得分:6)
当@a = ({1,2,3}, [1,2,3]);
超出范围时,其引用计数将减少一个*。
当引用计数@a
达到零时,其值的引用计数将减1,并且将被释放。
当引用计数$a[0]
(对哈希的引用)达到零时,引用哈希的引用计数将减1,并且将被释放。
当匿名哈希的引用计数达到零时,其值的引用计数将减1,并且将被释放。
当其中一个匿名散列值的引用计数达到零时,其值的引用计数将减1,并且将被释放。
同样适用于$a[1]
,它引用的数组以及该数组的值。
你可以通过使用具有析构函数的对象来“证明”这一点。
$ perl -E'
package X {
sub new { my ($c,$n) = @_; bless(\$n, $c) }
DESTROY { say ${$_[0]}; }
}
{
my @a = (
{ a => X->new(1), b => X->new(2) },
[ X->new(3), X->new(4) ],
);
say "Before end of scope";
}
say "After end of scope";
'
Before end of scope
4
3
2
1
After end of scope
* - 实际实施因优化而不同。
答案 1 :(得分:2)
如果你使用Scalar::Util的weaken
函数“弱化”它们,Perl可以垃圾收集循环引用:
weaken REF
REF will be turned into a weak reference. This means that it will
not hold a reference count on the object it references. Also when
the reference count on that object reaches zero, REF will be set to
undef.
对于垃圾收集超出范围的事情,没有人回答。这取决于您的操作系统以及perl的编译方式。这不是你一般应该担心的事情。 perlfaq3有几个相关条目:
答案 2 :(得分:0)
如果没有更多内容引用匿名哈希,它将被收集 This会给你一个完整的答案!
答案 3 :(得分:0)
另一种证明内部元素在超出范围时将被GC的方法:
use Scalar::Util 'weaken';
my $x;
{
my @a = ({foo => 'bar'}, ['foo', 'bar']);
$x = $a[1]; # ref to the inner array
weaken $x; # weaken the ref, so it doesn't interfere with GC
print "'$x->[1]'\n"; # show us what we got
}
print "'$x->[1]'\n"; # and now it's gone
输出:
'bar'
''
REF将变成弱参考。这意味着它 将不会持有参考计数 它引用的对象。也是当 该对象的引用计数达到 零,REF将设置为undef。
这对于保留副本很有用 参考,但你不想 防止对象被DESTROY-ed 通常的时间。
答案 4 :(得分:0)
实际上,当数组/哈希超出范围时,其values
(键中的引用只是作为字符串,因此不会影响refcount
)会减少refcount
,如果达到0
,则操作将递归执行。