【发布时间】:2010-06-04 06:46:00
【问题描述】:
与 Java 不同,Perl 使用引用计数进行垃圾收集。我曾尝试搜索一些关于 C++ RAII 和智能指针以及 Java GC 的先前问题,但不了解 Perl 如何处理循环引用问题。
谁能解释 Perl 的垃圾收集器如何处理循环引用?有没有办法回收程序不再使用的循环引用内存,或者 Perl 完全忽略了这个问题?
【问题讨论】:
标签: perl garbage-collection circular-reference
与 Java 不同,Perl 使用引用计数进行垃圾收集。我曾尝试搜索一些关于 C++ RAII 和智能指针以及 Java GC 的先前问题,但不了解 Perl 如何处理循环引用问题。
谁能解释 Perl 的垃圾收集器如何处理循环引用?有没有办法回收程序不再使用的循环引用内存,或者 Perl 完全忽略了这个问题?
【问题讨论】:
标签: perl garbage-collection circular-reference
根据我的Programming Perl 3rd ed.副本,在退出 Perl 5 时会执行“昂贵的标记和扫描”来回收循环引用。您需要尽可能避免循环引用,否则在程序退出之前它们不会被回收。
Perl 5 确实通过 Scalar::Utils 模块提供弱引用。
Perl 6 将转向可插入的垃圾收集方案(好吧,underlying VM will have multiple garbage collection options 和这些选项的行为会对 Perl 产生影响)。也就是说,您将能够在各种垃圾收集器之间进行选择,或者实现您自己的。想要一个复制收藏家?当然。想要着色器?你说对了。标记/扫描、压缩等?为什么不呢?
【讨论】:
快速回答是 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;
如果您在向数据结构中添加新节点时使用这样的代码,那么实际计算的对根的唯一引用是来自结构外部的引用。这正是你想要的。然后,一旦对它的最后一个外部引用消失,就会回收根及其所有子节点。
【讨论】:
【讨论】:
Perl 在某些情况下(我认为当一个线程死掉时)应用标记和清除备用 GC 以回收循环引用。请注意,“每个值都是字符串”Perl 节使得创建真正的循环引用变得困难;这是可行的,但“正常”的 Perl 代码不可行,这就是引用计数在 Perl 中运行良好的原因。
【讨论】:
sub leak { my $r; $r = \$r; } 虽然这是一个人为的例子,但在不注意的情况下做同样的事情并不难。
my $hashref = { a => 1 }; 留下 $hashref 作为实际参考,而不是字符串。自 17 年前 1994 年 10 月问世的 Perl 5 以来,情况就是如此。 (当然,Perl 很乐意将引用转换为字符串,但这种转换是单向的)