2010-06-04 128 views
12

与Java不同,Perl使用垃圾回收的引用计数。我曾尝试搜索一些前面提到的有关C++ RAII和智能指针和Java GC的问题,但尚未理解Perl如何处理循环引用问题。Perl中的垃圾回收

任何人都可以解释Perl的垃圾回收器如何处理循环引用?有什么办法可以回收程序不再使用的循环引用内存,或者Perl完全忽略这个问题?

回答

13

根据我的副本Programming Perl 3rd ed。,退出时,Perl 5会执行一个“昂贵的标记和扫描”来回收循环引用。您将尽可能避免循环引用,否则在程序退出前它们将不会被回收。

Perl 5确实通过Scalar::Utils模块提供了弱引用。

Perl 6将移动到一个可插拔的垃圾收集方案(嗯,underlying VM will have multiple garbage collection options和这些选项的行为可能会对Perl产生影响)。也就是说,你可以选择各种垃圾收集器,或者实现你自己的垃圾收集器。想要一个复制收藏家?当然。想要着色收藏家?你说对了。标记/扫描,压缩等?为什么不?

+4

Nit:Perl 5使用引用计数。这是一个垃圾收集计划。 – tsee 2010-06-04 09:54:51

+0

好的,我修改了对Perl 6垃圾回收的引用。 – 2010-06-04 17:29:08

+1

感谢您更新答案。注意:可插拔垃圾收集器看起来像一个可怕的想法。当堵塞垃圾收集器对GC时间做出不同承诺时,这是一种放慢速度和/或在远处产生可疑行为的好方法。 – tsee 2010-06-05 09:33:21

-8

Perl在某些情况下(当线程死亡时,我认为)应用标记和清除交替GC以回收循环引用。请注意,“每个值都是一个字符串”Perl节使创建真正的循环引用变得困难;这是可行的,但“正常的”Perl代码不会,这就是为什么引用计数与Perl很好地结合的原因。

+0

快速泄漏一个SV perl调用的方法'sub leak {my $ r; $ r = \ $ r; }' 虽然这是一个人为的例子,但不会注意到它的作用并不难。 – 2010-06-04 18:55:51

+7

这显然是错误的; Perl不*认为每个值都是一个字符串。 'my $ hashref = {a => 1};'将'$ hashref'作为实际参考,而不是字符串。自从Perl 5发布以来,这已经成为现实,它于10月** 1994年** - 17年前发布。 (当然,Perl会很高兴地将引用转换为一个字符串,但是这种转换是单向的) – derobert 2012-01-16 22:08:57

2

快速的回答是,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; 

如果使用这样当你添加新节点的数据结构的代码,然后到实际计数的根目录下唯一的引用是那些从结构之外。这正是你想要的。然后,当它的最后一个外部引用消失后,它的根和递归地所有子节点将被回收。