Вытекает ли интерпретатор Python 3 из памяти при встраивании? - PullRequest
4 голосов
/ 10 января 2012

В этом отчете об ошибке говорится, что интерпретатор Python по состоянию на июнь 2007 года не будет очищать всю выделенную память после вызова Py_Finalize в приложении C / C ++ со встроенным интерпретатором Python.Было рекомендовано вызывать Py_Finalize один раз при завершении работы приложения.

В этом отчете об ошибке говорится, что начиная с версии 3.3 и марта 2011 года интерпретатор все еще теряет память.

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

Я уже использую boost :: python для обработки счетчиков ссылок и очищаю глобальный словарьвсех ссылок, созданных при запуске программы Python между запусками.У меня есть несколько одноэлементных классов - могут ли это быть проблемой?

Это исправимая проблема или это ошибка в интерпретаторе Python?

1 Ответ

6 голосов
/ 10 января 2012

Вы можете видеть, что ошибка (первая, начиная с 2007 года) закрыта как "wontfix" nnorwitz, и его сообщение находится в отчете об ошибке.

Почему вы звоните Py_Initialize/Py_Finalize более одного раза? Почему бы не сделать что-то вроде этого (я вроде смешиваю C и Python для удобства):

/* startup */
Py_Initialize();

/* do whatever */
while (moreFiles()) {
    PyRun_SimpleString("execfile('%s')" % nextFile());
    /* do whatever */
}

/* shutdown */
Py_Finalize();

Проблема в том, что большинство людей, которые пишут модули Python, не беспокоятся о том, что произойдет, если их модуль будет финализирован и повторно инициализирован, и часто не заботятся об очистке во время финализации. Авторы модулей знают, что вся память освобождается при выходе из процесса, и не беспокоятся ни о чем, кроме этого.

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

Вы всегда можете просто пропустить вызов на Py_Finalize, вызов Py_Initialize во второй раз - бездействие. Это означает, что ваше приложение будет использовать дополнительную память при первом запуске скрипта Python, и эта дополнительная память не будет возвращена ОС до тех пор, пока вы не выйдете. Пока вы все еще время от времени запускаете скрипты Python, я бы не назвал это утечкой. Ваше приложение может быть не чистым от Valgrind, но оно лучше, чем протекает как сито.

Если вам нужно выгрузить ваши (чистые) модули Python, чтобы избежать утечки памяти, вы можете сделать это. Просто удалите их из sys.modules.

Недостатки Py_Finalize: Если вы выполняете скрипты Python повторно, запускать между ними Py_Finalize не имеет особого смысла. Вам придется перезагружать все модули каждый раз при повторной инициализации; мой Python загружает 28 модулей при загрузке.

Дополнительный комментарий: Ошибка не ограничивается Python. Значительное количество кода библиотеки на любом языке приведет к утечке памяти, если вы попытаетесь выгрузить и перезагрузить библиотеки. Многие библиотеки обращаются к C-коду, многие C-программисты предполагают, что их библиотеки загружаются один раз и выгружаются при выходе из процесса.

...