Python утечка памяти со сложным рабочим процессом - PullRequest
0 голосов
/ 30 марта 2020

Python 3 вопроса здесь. Я выискивал утечку памяти последние 3 дня и не могу ее найти. Мой код слишком сложен для публикации, но в основном REST API (flask) вызывает процедуру прогнозирования, которая, в свою очередь, вызывает субмодуль, который, в свою очередь, асинхронно выполняет одновременно тысячи вычислений, возвращая их общему объекту. В рабочем процессе есть много сложных структур данных, таких как словари фреймов данных. (Основные) глобальные переменные не используются, но некоторые функции ссылаются на нелокальные. В любом случае, при повторном запуске память взрывается.

Я сузил ее до подмодуля, и утечка все еще происходит, даже если асинхронная обработка отключена, и вот что сбивает с толку. Если я запускаю только подмодуль, выхожу из этой области и просматриваю переменные в отладчике Pycharm, ни одна из больших структур данных больше не находится в области видимости (что желательно). Но память не освобождается.

Я пробовал функционал в g c, как collect () и get_objects. Я также попробовал некоторые из различных библиотек, которые возвращают количество ссылок на типы. Очевидно, что ничто не взорвется подсчетом ссылок с точки зрения УВЕЛИЧЕНИЯ на один прогон, хотя я заметил, что у меня обычно 43 000 ссылок на «функцию» и 19 000 ссылок на «дикт», что меня очень беспокоит, что диктаты фреймов данных все еще как-то существуют , Я пробовал явные вещи, чтобы стереть диктовку, например, установив их в None, dict.clear () и del. Они запускаются, и отладчик говорит, что они ушли.

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

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

РЕДАКТИРОВАТЬ:

Хорошо, вот простой l oop, который концептуально не так сильно отличается от того, что я делаю. Он просто делает словарь из фреймов данных снова и снова. Когда я наблюдаю за памятью в этом примере, она ведет себя, как и ожидалось, скачки памяти, а затем падает на каждой итерации. Теперь в моем реальном коде (который намного сложнее) ... мы видим увеличение памяти, но затем по возвращении оно не уменьшается.

Так, что, концептуально, было бы причиной этого. Не удаленные ссылки на dict или на базовые кадры данных, верно? Я посмотрел на вывод objgraph и нет обратных ссылок, которые не должны быть удалены при возврате функции. (Но я думаю, что должно быть).

Еще одна мысль: единственная обратная ссылка на кадры данных в objgraph - это кортеж. Теперь это произошло потому, что в моем действительном l oop создается фрейм данных, который заканчивается множеством возвращаемых значений, переданных в виде кортежа, например, inner_sub_fun c () возвращает (float, float, int, DataFrame). Я думаю, что этот фактический кортеж все еще плавает в конце моей основной функции. Но как только основная функция завершится и мы вернемся к main , так сказать, разве этот кортеж не должен быть уничтожен?

def func():
    DICT_OF_DF = {}
    for i in range (0, 1000):
        DICT_OF_DF[i] = pd.DataFrame(np.random.random([1000, 1000]))
    DICT_OF_DF.clear()
    del DICT_OF_DF
    gc.collect()
    return 42

for j in range(0, 100000):
    print('Running func #{}'.format(j))
    func()
    debug = True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...