Циркулярные ссылки
на сегодняшний день являются наиболее распространенными
канонической причиной утечек.
sub leak {
my ($foo, $bar);
$foo = \$bar;
$bar = \$foo;
}
Perl использует ссылку подсчета мусора. Это означает, что perl хранит подсчет того, какие указатели на любую переменную существуют в данный момент времени. Если переменная выходит за пределы области действия, а число равно 0, переменная очищается.
В примере кода выше, $foo
и $bar
никогда не собираются и копия будет сохраняться после каждого вызова leak()
, поскольку обе переменные имеют счетчик ссылок 1.
Самый простой способ избежать этой проблемы заключается в использовании слабые ссылки. Слабые ссылки - это ссылки, которые вы используете для доступа к данным, но не учитываете сбор мусора.
use Scalar::Util qw(weaken);
sub dont_leak {
my ($foo, $bar);
$foo = \$bar;
$bar = \$foo;
weaken $bar;
}
В dont_leak()
, $foo
имеет счетчик ссылок 0, $bar
имеет порядковый отсчет, равный 1. Когда мы оставить объем подпрограммы, $foo
возвращается к бассейну, и его ссылка на $bar
очищается. Это уменьшает количество ссылок на $bar
до 0, что означает, что $bar
также может вернуться в бассейн.
Обновление: brain d foy спросил, есть ли у меня какие-либо данные для подтверждения моего утверждения о том, что циркулярные ссылки являются общими. Нет, у меня нет статистики, чтобы показать, что циркулярные ссылки являются общими. Они чаще всего обсуждаются и являются наиболее документированной формой утечек памяти perl.
Мое впечатление, что они происходят. Вот краткое описание утечек памяти, которые я видел более десяти лет работы с Perl.
У меня были проблемы с приложениями pTk, развивающими утечки. Некоторые утечки, которые я смог доказать, были вызваны круговыми ссылками, которые возникли, когда Tk передает ссылки на окна. Я также видел pTk утечки, причиной которых я никогда не мог отследить.
Я видел, как люди неправильно понимают weaken
и заканчивают круговыми ссылками случайно.
Я видел непреднамеренные циклы, когда слишком много плохо продуманных объектов бросаются вместе в спешке.
Однажды я обнаружил утечки памяти, которые исходили от модуля XS, который создавал большие, глубокие структуры данных. Я никогда не мог получить воспроизводимый тестовый пример, который был меньше, чем вся программа. Но когда я заменил модуль другим сериализатором, утечки исчезли. Поэтому я знаю, что эти утечки исходили от XS.
Итак, по моему опыту, циклы являются основным источником утечек.
К счастью, there is a module, чтобы помочь отследить их.
Что касается больших глобальных структур, которые никогда не очищаются, это «утечки», я согласен с Брайаном. Они взлетают подобно утечкам (у нас постоянно растет использование памяти процесса из-за ошибки), поэтому они являются утечками. Тем не менее, я не помню, чтобы когда-либо видел эту проблему в дикой природе.
Основываясь на том, что я вижу на сайте Стоунхенджа, я предполагаю, что Брайан видит много больного кода от людей, которых он обучает или претворяет целебные чудеса. Таким образом, его набор образцов легко намного больше и разнообразнее, чем у меня, но у него есть свой собственный выбор.
Какая причина утечек наиболее распространена? Я не думаю, что мы когда-нибудь узнаем. Но мы все можем согласиться с тем, что циркулярные ссылки и глобальные свалки данных являются анти-шаблонами, которые необходимо устранить там, где это возможно, и обрабатывать с осторожностью и осторожностью в тех немногих случаях, когда они имеют смысл.
Как вы поймали эти утечки памяти? Вы пробовали Perl Profiler (http://www.perlmonks.org/?node_id=472366)? –