Может ли слишком частое ведение журнала резко увеличивать размер кучи?

#java #memory-leaks #log4j #resource-leak

#java #утечки памяти #log4j #утечка ресурсов

Вопрос:

Я расследую резкое увеличение объема памяти, происходящее в процессе Java. Я вижу, что размер кучи растет до 3-4 ГБ. После расследования я вижу, что в классе происходит ведение журнала (что происходит очень часто, например, каждые 1 или 2 мс), что создает около 4 МБ журналов за 1 секунду. Так что, по моему мнению, это и есть причина увеличения размера кучи. Кроме того, размер кучи не уменьшается после того, как код выходит из класса и ведение журнала прекращается. Процесс заключается в использовании log4j-1.2.16.jar .

У меня есть вопросы ниже.

  1. log4j создает слишком много объектов в куче из-за частого ведения журнала? Если да, является ли это ожидаемым поведением или это какое-то ограничение в log4j, которое решается в log4j2?
  2. Почему размер кучи не уменьшается? Содержит ли log4j ссылку на объекты в куче, поскольку они не собираются GC?

Пожалуйста, помогите мне понять это поведение log4j и jvm. Я не знаю, известно ли это, и log4j2 обратился к этому вопросу.

Ответ №1:

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

Просмотрите сообщения и проверьте уровень детализации. Ключевой проблемой является печать слишком большого количества сообщений или кода, который не проверяет уровень ведения журнала, поскольку строковое выражение вычисляется, даже если сообщение не требуется. Это может быть причиной большого и ненужного выделения памяти. Рассмотрим:

 logger.debug("This line causes memory allocations even if not printed: "  value);
 

Если вы изменили уровень ведения журнала на WARN , приведенная выше конкатенация строк для сообщения все равно выполняется, и если value.toString() это дорогостоящая операция с памятью, будет еще больше ненужных выделений объектов в дополнение к вызовам StringBuilder, добавленным JVM. Измените свои вызовы log4j, чтобы проверить уровень перед регистрацией:

 if (logger.isDebugEnabled()) {
    logger.debug("The value is: "  value);
}
logger.debug("No need to call logger.isDebugEnabled() for a string literal");
 

С log4j2 вы можете регистрироваться с помощью строк формата или Supplier<String> , а конкатенации строк для сообщения журнала оцениваются только тогда, когда сообщение требуется.

Запись в System.out может быть дорогостоящей, поэтому убедитесь, что в консоли отображаются только информационные сообщения, и используйте приложение, чтобы сообщения ОТЛАДКИ отправлялись в файлы журнала.