Анализ утечки памяти кода PythonПроанализированы некоторые утечки памяти и кратко представлено использованиеobjgraph, gcи другие инструменты. В сочетании с некоторыми реальными ситуациями здесь мы запишем фактические проблемы, возникающие при устранении утечек памяти.
где память
Наблюдайте за изменениями памяти процесса Python на сервере. Когда обнаруживается, что процесс Python растет во время выполнения, существует потенциальный риск утечки. При устранении неполадок, связанных с утечкой объектов Python через objgraph и т. д., часто требуется, чтобы они находились в относительно стабильном состоянии. Если текущий процесс занят и объекты создаются часто, даже если в objgraph видно большое количество объектов, трудно определить, действительно ли это утечка. Когда процесс больше не обрабатывает новую логику запроса на обработку, наблюдайте за использованием памяти текущим процессом, а затем ищите объекты Python с помощью objgraph, найти проблему несложно. Объекты Python, которые в настоящее время можно подсчитать, не занимают столько памяти. Куда уходит эта память?
пройти черезguppyВы можете рассчитать и подсчитать потребление памяти объектами Python в текущем процессе и сравнить использование памяти, показанное в Top. Обычно оказывается, что объем памяти, полученный в гуппи, намного меньше, чем память, занимаемая процессом в данный момент.gdb-heapИнструменты вроде . Так что же именно занимает эту часть памяти? На самом деле вполне вероятно, что только память занята собственным механизмом выделения Python, см.diagnosing-memory-leaks-python. Как это определить?
Прямой анализ памяти процесса
существуетздесьВы можете найти скрипт, который сбрасывает память процесса,
#!/bin/bash
grep rw-p /proc/$1/maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' | while read start stop; do gdb --batch --pid $1 -ex "dump memory $1-$start-$stop.dump 0x$start 0x$stop"; done
Чтобы экспортировать сгенерированный файл, используйте следующую команду:
strings -n 10 ...
Чтобы найти строковое содержимое в файле, длина которого превышает определенный диапазон, и определить, какая часть содержимого занимает память, из данных содержимого. В случае реальных утечек памяти соответствующая информация должна быть найдена в файле, соответствующем куче. При отсутствии утечек сложно проанализировать, что в куче. Причиной этого может быть механизм памяти Python. Когда эта проблема очевидна, возможная скрытая проблема заключается в том, что памяти процесса выделяется слишком много, что приводит к тому, что процесс всегда обращается за памятью, как и система.Конечным проявлением является то, что память процесса продолжает увеличиваться, но когда процесс простаивает, он не может быть извлечен из objgraph.Непосредственно видеть утечку объекта.
Анализ через objgraph
Вернемся к объектному графику. Поскольку источник проблемы находится в коде Python, должна быть возможность отследить трассировку через objgraph. Как упоминалось выше, через objgraph относительно легко анализировать, когда процесс простаивает, но для решения вышеуказанных проблем необходимо вмешиваться, когда процесс занят.
объектный графикobjgraph.show_most_common_types
Максимальное количество информации о типе может быть возвращено. Если это пользовательский тип, то проблема легко решается. Если это примитивный тип, такой какdict
,list
Что я должен делать? Нативные типы, как правило, многочисленны, а обычные данные об утечке данных перемешаны друг с другом. В этом случае невозможно напрямую пройтиobjgraph.find_backref_chain
и т. д., чтобы следовать цепочке ссылок. Очень простой, но очень эффективный метод — экспортировать данные в файл, а затем проанализировать их. Если утекшие данные можно найти, даже если нет цепочки ссылок, их легко проанализировать в коде.
Кратко опишите конкретные шаги на примере данных dict.
- Получить все текущие объекты dict
dict_list = objgraph.by_type('dict')
- Запишите полученный список в файл по порядку, дикт выводит одну строку с номером строки
def save_to_file(self, name, items):
with open(name, 'w') as outputs:
for idx, item in enumerate(items):
try:
outputs.write(str(idx) + " ### ")
outputs.write(str(item))
outputs.write('\n')
except Exception as e:
print e
outputs.flush()
-
Реализуйте сценарий для анализа выходного файла и его обработки в сочетании с командами grep, sed и awk. Проанализируйте и подсчитайте, сколько существует дикторов разной длины, сколько дикторов имеют одинаковую структуру (один и тот же ключ) и т. д. Диктант, вызывающий проблему, получается путем анализа.
-
В соответствии с информацией о номере строки, соответствующей просочившемуся словарю, получите эталонное отношение через objgraph или проанализируйте его непосредственно из кода.
objgraph.find_backref_chain(dict_list[idx], objgraph.is_proper_module)
Суммировать
Когда память процесса продолжает расти и не возвращается в систему, обычно имеет место настоящая утечка, а второе — запросов памяти больше, чем релизов. С первым справиться относительно легко. Но общая идея борьбы с ней заключается в том, чтобы найти объект, вызвавший проблему. Лучше всего, если проблемный объект можно найти непосредственно с помощью таких инструментов, как objgraph. Если вы не можете найти его напрямую, рассмотрите глупый способ экспорта данных для анализа и обработки. Память должна быть чем-то занята, и проблему можно найти относительно интуитивно по данным. В конце концов, проблемы с памятью обычно вызываются глобальными синглтонами, глобальными кэшами и долгоживущими объектами.После работы с этой частью кода с общей памятью возникают проблемы.