Профилирование использования памяти Perl и обнаружение утечек? - PullRequest
33 голосов
/ 01 сентября 2009

Я написал постоянную сетевую службу на Perl, которая работает на Linux.

К сожалению, при запуске размер резидентного стека (RSS) просто растет, растет и растет медленно, но верно.

Это, несмотря на все мои усердные усилия по удалению всех ненужных хеш-ключей и удалению всех ссылок на объекты, которые в противном случае привели бы к тому, что счетчики ссылок остались на месте, и мешали бы сборке мусора.

Существуют ли в Perl-программах хорошие инструменты для профилирования использования памяти, связанного с различными собственными примитивами данных, объектами ссылок с благословенными хэшами и т. Д.? Что вы используете для отслеживания утечек памяти?

Я обычно не провожу время в отладчике Perl или любом другом интерактивном профилировщике, поэтому приветствуется теплый, мягкий, неэзотерический ответ. : -)

Ответы [ 5 ]

14 голосов
/ 01 сентября 2009

У вас может быть круговая ссылка в одном из ваших объектов. Когда сборщик мусора приходит, чтобы освободить этот объект, циклическая ссылка означает, что все, на что ссылается эта ссылка, никогда не освободится. Вы можете проверить циклические ссылки с помощью Devel :: Cycle и Test :: Memory :: Cycle . Одна из вещей, которую нужно попробовать (хотя в производственном коде это может дорого обойтись, поэтому я бы отключил ее, если не установлен флаг отладки), проверяет циклические ссылки внутри деструктора для всех ваших объектов:

# make this be the parent class for all objects you want to check;
# or alternatively, stuff this into the UNIVERSAL class's destructor
package My::Parent;
use strict;
use warnings;
use Devel::Cycle;   # exports find_cycle() by default

sub DESTROY
{
    my $this = shift;

    # callback will be called for every cycle found
    find_cycle($this, sub {
            my $path = shift;
            foreach (@$path)
            {
                my ($type,$index,$ref,$value) = @$_;
                print STDERR "Circular reference found while destroying object of type " .
                    ref($this) . "! reftype: $type\n";
                # print other diagnostics if needed; see docs for find_cycle()
            }
        });

    # perhaps add code to weaken any circular references found,
    # so that destructor can Do The Right Thing
}
10 голосов
/ 01 сентября 2009

Вы можете использовать Devel :: Leak для поиска утечек памяти. Тем не менее, документация довольно скудная ... например, где взять ссылку на дескриптор $ для передачи в Devel::Leak::NoteSV()? f Я найду ответ, я отредактирую этот ответ.

Хорошо, получается, что использовать этот модуль довольно просто (код, бесстыдно украденный из Apache :: Leak ):

use Devel::Leak;

my $handle; # apparently this doesn't need to be anything at all
my $leaveCount = 0;
my $enterCount = Devel::Leak::NoteSV($handle);
print STDERR "ENTER: $enterCount SVs\n";

#  ... code that may leak

$leaveCount = Devel::Leak::CheckSV($handle);
print STDERR "\nLEAVE: $leaveCount SVs\n";

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

4 голосов
/ 01 сентября 2009

Что дальше попробовать (не уверен, что это будет лучше всего поместить в комментарии после вопроса Алекса выше): Что я попробую дальше (кроме Devel :: Leak):

Попытайтесь исключить «ненужные» части вашей программы или разбить ее на отдельные исполняемые файлы (они могут использовать сигналы для связи или вызывать друг друга с аргументами командной строки) - цель состоит в том, чтобы выкипать исполняемый файл с наименьшим количеством кода, который все еще демонстрирует плохое поведение . Если вы уверены, что это делает не ваш код, уменьшите количество используемых внешних модулей, особенно тех, которые имеют реализацию XS. Если возможно это ваш собственный код, поищите что-нибудь потенциально подозрительное:

  • определенно любое использование Inline :: C или XS кода
  • прямое использование ссылок, например, \@list или \%hash, а не предварительно выделенные ссылки, такие как [qw (foo bar)] (первая создает другую ссылку, которая может быть потеряна; во второй есть только одна ссылка для беспокойства, которая обычно хранится в местный лексический скаляр
  • косвенное управление переменными, например, $$foo, где $foo изменено, что может вызвать автововлечение переменных (хотя вам необходимо отключить проверку strict 'refs')
3 голосов
/ 14 сентября 2010

Я недавно использовал NYTProf в качестве профилировщика для большого Perl-приложения. Он не отслеживает использование памяти, но отслеживает все пути исполняемого кода, что помогает выяснить, откуда происходят утечки. Если то, что вы пропускаете, это дефицитные ресурсы, такие как соединения с базой данных, то отслеживание того, где они размещены и закрыты, имеет большое значение для обнаружения утечек.

2 голосов
/ 03 ноября 2009

Хорошее руководство по этому вопросу включено в руководство по Perl: Отладка использования памяти Perl

...