Как я могу найти утечки памяти в долго работающей программе Perl?

Другие ответы в этой теме связаны с boto, но S3.Object больше не повторяется в boto3. Таким образом, следующее НЕ РАБОТАЕТ, оно выдает сообщение об ошибке TypeError: 's3.Object' object is not iterable:

    s3 = boto3.session.Session(profile_name=my_profile).resource('s3')
    s3_obj = s3.Object(bucket_name=my_bucket, key=my_key)

    with io.FileIO('sample.txt', 'w') as file:
        for i in s3_obj:
            file.write(i)

В boto3 содержимое объекта доступно в S3.Object.get()['Body'], которое также не является итерируемым, поэтому следующий еще НЕ РАБОТАЕТ:

    body = s3_obj['Body']
    with io.FileIO('sample.txt', 'w') as file:
        for i in body:
            file.write(i)

Итак, альтернативой является использование метода чтения, но это загружает объект WHOLE S3 в память, который при работе с большими файлами не всегда возможен:

    body = s3_obj['Body']
    with io.FileIO('sample.txt', 'w') as file:
        for i in body.read():
            file.write(i)

Но метод read позволяет передать в amt параметр, определяющий количество байтов, которые мы хотим прочитать из базового потока. Этот метод можно многократно вызывать до тех пор, пока весь поток не будет прочитан:

    body = s3_obj['Body']
    with io.FileIO('sample.txt', 'w') as file:
        while file.write(body.read(amt=512)):
            pass

Копаем в код botocore.response.StreamingBody, понимаем, что базовый поток также доступен, поэтому мы могли бы выполнять итерацию следующим образом:

    body = s3_obj['Body']
    with io.FileIO('sample.txt', 'w') as file:
        for b in body._raw_stream:
            file.write(b)

В то время как googling я также видел некоторые ссылки, которые могут быть использованы, но я не пробовал:

37
задан taw 9 January 2009 в 18:53
поделиться

4 ответа

Может быть важно, что Perl никогда не отдает память к системе отдельно: это - все до malloc() и все правила, связанные с этим.

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

Может случиться так, что можно реорганизовать программу для использования в своих интересах этого факта - путем вызова undef($old_object) явно - и в правильном порядке, способом, подобным пути, C-программисты говорят free(old_object);

Для продолжительных программ (дни, месяцы, и т.д.), где у меня есть загрузки циклов загрузки/копии/дампа, я собираю "мусор" с помощью exit() and exec(), и где это otherwide невыполнимый, я просто собираю свои структуры данных (использование Storable) и дескрипторы файлов (использование $^F) и exec($0) - обычно с набором переменной среды как $ENV{EXEC_GC_MODE}, и Вам, возможно, понадобится что-то подобное, даже если у Вас нет собственных утечек просто, потому что Perl пропускает маленькие блоки что Ваша система malloc() не может выяснить, как отдать.

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


Все утечки памяти программ жемчуга или будут XS, содержащим на ссылку или круговую структуру данных. Devel:: Цикл является большим инструментом для нахождения циклических ссылок, если Вы знаете, какие структуры, вероятно, будут содержать циклы. Devel:: Быстрый взгляд может использоваться для нахождения объектов с более высоким, чем ожидалось подсчетом ссылок.

Если Вы не знаете, где еще посмотреть, Devel:: LeakTrace:: Быстро могло быть хорошее первое место, но Вам будет нужен жемчуг, созданный для отладки.

Если Вы подозреваете, что утечкой является внутреннее XS-пространство, это намного более твердо, и Valgrind, вероятно, будет Вашим лучшим выбором. Тест:: Valgrind может помочь Вам понизить объем кода, который необходимо искать, но это не будет работать над Windows, таким образом, необходимо было бы портировать (по крайней мере, текучая часть) к Linux, чтобы сделать это.

36
ответ дан Community 9 January 2009 в 18:53
поделиться
  • 1
    +1, В то время как у нас есть главным образом подобные ответы, Ваша разбивка части B превосходит мою. – corsiKa 4 April 2011 в 20:22

Devel:: Гладиатор является другим полезным инструментом в этом пространстве.

5
ответ дан derobert 9 January 2009 в 18:53
поделиться
  • 1
    +1 для самостоятельно назначенного предела для c – RichardTheKiwi 6 April 2011 в 10:48

Походит на cpan модуль Devel:: Цикл - то, что Вы ищете. Это требует внесения некоторых изменений в Ваш код, но это должно помочь Вам найти свои ссылки без слишком многих проблем.

3
ответ дан Craig H 9 January 2009 в 18:53
поделиться
  • 1
    Я пытался думать о примере для (c) где они don' t явно взаимодействуют. Лучшее, о котором я мог думать, было то, что они оба сделали различную работу над чем-то (веб-страница, файл на диске, блоке памяти), который мог кэшироваться, если бы они оба запросили его. – Jack V. 12 December 2011 в 13:29

valgrind является большим приложением Linux, которое определяет местоположение утечек памяти в рабочем коде. Если Ваш код Perl работает на Linux, необходимо проверить его.

3
ответ дан Yuval F 9 January 2009 в 18:53
поделиться
  • 1
    @JackV.: Любой вид расположения производителя/потребителя с двумя потребителями соответствовал бы описанию для (c). Но работа может также быть разделена заранее (например, сортировка большого файла с делением и завоевать и более позднее слияние результатов). – Jon 12 December 2011 в 14:05
Другие вопросы по тегам:

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