2010-06-04 2 views
12

В отличие от Java, Perl использует счетчик ссылок для сбора мусора. Я попытался найти некоторые предыдущие вопросы, которые говорят о C++ RAII и интеллектуальных указателях и Java GC, но не понял, как Perl имеет дело с круговой ссылкой.Сбор мусора в Perl

Может ли кто-нибудь объяснить, как сборщик мусора Perl имеет дело с круговыми ссылками? Есть ли способ вернуть круговую обратную память, которая больше не используется программой или Perl просто полностью игнорирует эту проблему?

ответ

13

Согласно моей копии Программирование 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

+0

ОК, я изменил ссылку на сборку мусора Perl 6. –

+1

Спасибо за обновление ответа. NB: Подключаемые сборщики мусора кажутся ужасной идеей. Отличный способ замедлить работу и/или вызвать сомнительные действия на расстоянии при подключении сборщиков мусора, которые дают разные обещания о времени GC. – tsee

-8

В некоторых случаях (когда нить умирает, я думаю) Perl применяет альтернативный GC с меткой и разметкой, чтобы вернуть круговые ссылки. Обратите внимание, что «каждое значение является строкой». Строка Perl затрудняет создание настоящих круговых ссылок; это возможно, но «нормальный» код Perl этого не делает, поэтому подсчет ссылок хорошо работает с Perl.

+0

Быстрый способ утечки одного вызова SV perl 'sub leak {my $ r; $ r = \ $ r; } ' Хотя это надуманный пример, нетрудно сделать эквивалент, не заметив его. –

+7

Это просто неправильно; Perl does * not * считает, что каждое значение является строкой. 'my $ hashref = {a => 1};' оставляет '$ hashref' как фактическую ссылку, а не строку. Это было верно с Perl 5, который вышел в октябре ** 1994 ** - 17 лет назад. (Конечно, Perl с радостью преобразует ссылку на строку, но это преобразование одностороннее) – derobert

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; 

Если вы используете код, как это всякий раз, когда вы добавляете новые узлы в вашей структуре данных, то только ссылки на корню, которые на самом деле являются подсчитывались снаружи структуры. Это именно то, что вы хотите. Тогда корень и рекурсивно все его дети будут возвращены, как только последняя внешняя ссылка на него исчезнет.