Многопоточное приложение Python с утечкой памяти из потоковых экземпляров регистратора - PullRequest
2 голосов
/ 17 июня 2011

У меня есть серверные подклассы, порождающие обработчики ответных потоков, которые в свою очередь запускают потоки приложений. Все идет гладко, за исключением случаев, когда я использую ObjGraph . Я вижу правильное число запущенных потоков приложений (я выполняю нагрузочное тестирование, и его регулируют, чтобы поддерживать работу 35 экземпляров приложений).

Вызов objgraph.typestats () обеспечивает разбивку того, сколько экземпляров каждого объекта в данный момент находится в интерпретаторе (согласно GC). Глядя на этот вывод на предмет утечек памяти, я нахожу 700 экземпляров регистратора - это будет общее количество обработчиков ответов, порожденных сервером.

Я вызвал logger.removehandler (memoryhandler) и logger.removehandler (filehandler), когда поток приложения выходит из метода run (), чтобы убедиться, что нет никаких устаревших ссылок на экземпляры регистратора, а также экземпляры регистратора полностью изолированы внутри поток приложения (на него нет внешних ссылок). В качестве последнего шага при устранении этих экземпляров регистратора последний оператор в run () является del self.logger

Чтобы получить регистратор в init (), я предоставляю ему достаточно большое случайное число, чтобы присвоить ему имя, чтобы оно было разным для доступа к файлу - я использую то же большое число в качестве части имени файла журнала, чтобы избежать коллизий журнала приложения.

Если коротко, то у меня есть 700 экземпляров регистратора, отслеживаемых ГХ, но только 35 активных потоков - как мне убить этих регистраторов? Более громоздкое инженерное решение - создать пул логгеров и просто приобрести его на весь срок службы потока приложения, но при этом создается больше кода для обслуживания, когда GC просто должен обработать это автоматически.

Ответы [ 2 ]

0 голосов
/ 01 апреля 2014

Я столкнулся с той же утечкой памяти при использовании logging.Logger (), и вы можете попытаться вручную закрыть обработчик fd, когда регистратор бесполезен, например:

for handler in logger.handlers:
    handler.close()
0 голосов
/ 17 июня 2011

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

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

logger = logging.getLogger(__name__)

, что достаточно для большинства сценариев.

Из вашего вопроса я не могу сказать, понимаете ли вы, что обработчики и регистраторы - это не одно и то же - например, вы говорите о вызовах removeHandler (которые могут служить для освобождения экземпляров обработчиков, поскольку их счетчики обращаются в ноль, но при этом вы не освободите экземпляры регистратора).

Как правило, регистраторы именуются по частям вашего приложения, которые генерируют интересующие вас события.

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

...