Общая память/ссылка Perl пропускает шаблоны?

Я преследую несколько потенциальных утечек памяти в кодовой базе Perl, и я хотел бы знать о распространенных ошибках относительно памяти (неправильное) управление в Perl.

Что такое общие шаблоны утечки, которые Вы наблюдали в коде Perl?

14
задан knorv 8 February 2010 в 18:01
поделиться

4 ответа

Циркулярные ссылки являются наиболее распространенной канонической причиной утечек.

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 также может вернуться в пул.

Обновление: мозг спросил, есть ли у меня данные, подтверждающие мое утверждение о том, что циклические ссылки являются обычным явлением. Нет, у меня нет статистики, показывающей, что циклические ссылки - обычное дело. Это наиболее часто обсуждаемая и наиболее документированная форма утечек памяти Perl.

Мой опыт показывает, что они действительно случаются. Вот краткое изложение утечек памяти, которые я наблюдал за десять лет работы с Perl.

У меня были проблемы с утечками приложений pTk. Некоторые утечки, которые мне удалось доказать, были связаны с циклическими ссылками, которые возникали, когда Tk передает ссылки на окна. Я также видел утечки pTk, причину которых я никогда не мог отследить.

Я видел, как люди неправильно понимают , ослабляют и случайно заканчивают круговыми ссылками.

Я видел непреднамеренные циклы, когда слишком много плохо продуманных объектов собирались вместе в спешке.

Однажды я обнаружил утечку памяти из-за модуля XS, который создавал большие и глубокие структуры данных.Мне никогда не удавалось получить воспроизводимый тестовый пример меньше, чем вся программа. Но когда я заменил модуль другим сериализатором, утечки исчезли. Итак, я знаю, что утечки исходили от XS.

Итак, по моему опыту, циклы являются основным источником утечек.

К счастью, есть модуль , который поможет их выследить.

Что касается того, являются ли большие глобальные структуры, которые никогда не очищаются, «утечками», я согласен с Брайаном. Они крякают как утечки (у нас постоянно растет использование памяти процессами из-за ошибки), так что это утечки. Даже в этом случае я не припомню, чтобы когда-либо видел эту конкретную проблему в дикой природе.

Основываясь на том, что я вижу на сайте Стоунхенджа, я предполагаю, что Брайан видит много нездорового кода от людей, которых он тренирует или для которых готовит чудеса исцеления. Таким образом, его выборочный набор намного больше и разнообразен, чем мой, но он имеет свою собственную предвзятость отбора.

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

19
ответ дан 1 December 2019 в 07:39
поделиться

Если проблема в коде Perl, у вас может быть ссылка, которая указывает на себя или родительский узел.

Обычно он имеет форму объекта, который ссылается на родительский объект.

{ package parent;
  sub new{ bless { 'name' => $_[1] }, $_[0] }
  sub add_child{
    my($self,$child_name) = @_;
    my $child = child->new($child_name,$self);
    $self->{$child_name} = $child;   # saves a reference to the child
    return $child;
  }
}
{ package child;
  sub new{
    my($class,$name,$parent) = @_;
    my $self = bless {
      'name' => $name,
      'parent' => $parent # saves a reference to the parent
    }, $class;
    return $self;
  }
}
{
  my $parent = parent->new('Dad');
  my $child  = parent->add_child('Son');

  # At this point both of these are true
  # $parent->{Son}{parent} == $parent
  # $child->{parent}{Son}  == $child

  # Both of the objects **would** be destroyed upon leaving
  # the current scope, except that the object is self-referential
}

# Both objects still exist here, but there is no way to access either of them.

Лучший способ исправить это - использовать Scalar :: Util :: weaken .

use Scalar::Util qw'weaken';
{ package child;
  sub new{
    my($class,$name,$parent) = @_;
    my $self = bless {
      'name' => $name,
      'parent' => $parent
    }, $class;

    weaken ${$self->{parent}};

    return $self;
  }
}

Я бы рекомендовал удалить ссылку на родительский объект из дочернего, если это вообще возможно.

9
ответ дан 1 December 2019 в 07:39
поделиться

В прошлом у меня были проблемы с XS, как с моими собственными руками, так и с модулями CPAN, где утечка памяти происходит внутри кода C, если она не управляется должным образом. Мне так и не удалось отследить утечки; проект был в сжатые сроки и имел фиксированный срок эксплуатации, поэтому я скрыл эту проблему с помощью ежедневной перезагрузки cron . cron действительно замечательный.

5
ответ дан 1 December 2019 в 07:39
поделиться

Некоторые модули из CPAN используют циклические ссылки для выполнения своей работы, например HTML :: TreeBuilder (который представляет дерево HTML). В конце они потребуют, чтобы вы запустили какой-нибудь метод / процедуру разрушения. Просто прочтите документацию :)

2
ответ дан 1 December 2019 в 07:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: