与Java不同,Perl使用引用计数进行垃圾收集。我曾尝试搜索一些以前的问题,这些问题涉及C ++ RAII和智能指针以及Java GC,但还没有理解Perl如何处理循环引用问题。
任何人都可以解释Perl的垃圾收集器如何处理循环引用?有没有办法回收程序不再使用的循环引用内存,或者Perl是否完全忽略了这个问题?
答案 0 :(得分:13)
根据我的 Programming Perl 3rd ed。的副本,在退出时,Perl 5执行“昂贵的标记和扫描”来回收循环引用。您希望尽可能避免循环引用,否则在程序退出之前不会回收它们。
Perl 5通过Scalar::Utils模块提供弱引用。
Perl 6将转移到可插入垃圾收集方案(好吧,underlying VM will have multiple garbage collection options,这些选项的行为可能会对Perl产生影响)。也就是说,您可以在各种垃圾收集器之间进行选择,也可以实现自己的垃圾收集器。想要一个复制收藏家?当然。想要一个着色收藏家?你说对了。标记/扫描,压缩等?为什么不呢?
答案 1 :(得分:3)
快速回答是Perl 5自动不处理循环引用。除非在代码中采取明确的措施,否则在创建它们的线程消失之前,不会回收包含循环引用的任何数据结构。这被认为是一种可接受的权衡,因为它避免了运行时垃圾收集的需要,这会减慢执行速度。
如果您的代码使用循环引用创建数据结构(即,其节点包含返回根目录的树的树),您将需要使用Scalar :: Util模块来减弱"弱化"指向根节点的引用。这些弱引用不会添加它们指向的引用计数,因此当最后一个外部引用消失时,整个数据结构将自动解除分配。
示例:
use Scalar::Util qw(weaken);
...
my $new_node = { content => $content, root => $root_node };
weaken $new_node->{root};
push @{$root_node->{children}}, $new_node;
如果在向数据结构添加新节点时使用这样的代码,则实际计算的对根的唯一引用是来自结构外部的引用。这正是你想要的。然后,一旦它的最后一个外部引用消失,它将以递归方式返回其所有子节点。
答案 2 :(得分:1)
答案 3 :(得分:-8)
Perl在某些情况下(当线程死亡时,我认为)应用了标记和扫描备用GC,以便回收循环引用。请注意,“每个值都是一个字符串”Perl节使得创建真正的循环引用变得困难;这是可行的,但“普通”Perl代码没有,这就是为什么引用计数与Perl一起使用的原因。