Сборка мусора в Perl

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

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

4 ответа

Решение

Согласно моей копии программирования Perl 3-е изд. На выходе Perl 5 делает "дорогую метку и зачистку", чтобы вернуть циклические ссылки. Вы будете стараться избегать циклических ссылок в максимально возможной степени, потому что в противном случае они не будут возвращены до выхода из программы.

Perl 5 предлагает слабые ссылки через модуль Scalar::Utils.

Perl 6 перейдет к подключаемой схеме сборки мусора (у базовой виртуальной машины будет несколько параметров сборки мусора, и поведение этих параметров может повлиять на 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.

Другие вопросы по тегам