Подтвердить что ты не робот

Использование профилей памяти Perl и обнаружение утечки?

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

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

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

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

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

4b9b3361

Ответ 1

У вас может быть круговая ссылка на одном из ваших объектов. Когда сборщик мусора приходит, чтобы освободить этот объект, круговая ссылка означает, что все, о чем говорится в этой ссылке, никогда не будет освобождено. Вы можете проверить круговые ссылки 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 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
}

Ответ 2

Вы можете использовать Devel::Leak для поиска утечек памяти. Тем не менее, документация довольно редкая... например, где же получить ссылку $handle для перехода на 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";

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

Ответ 3

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

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

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

Ответ 5

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