2010-06-04 93 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; 

如果使用這樣當你添加新節點的數據結構的代碼,然後到實際計數的根目錄下唯一的引用是那些從結構之外。這正是你想要的。然後,當它的最後一個外部引用消失後,它的根和遞歸地所有子節點將被回收。