Вопрос или проблема
У меня есть приложение на Spring Boot с WebFlux, которое использует Log4j2 для логирования. Я использую последнюю версию Spring Boot starter 3.3.3 и его log4j2. Когда я провел тест производительности, оно потребляло много памяти и вызывало серьезные события сборки мусора.
Когда я сделал дамп кучи и экспортировал его в MAT, он указал на 3 компонента как на подозреваемые утечки.
Log4jLoggerFactory -> 60.45 МБ Logger -> 9,82,392 (объекта) -> занимает 119.92 МБ Строка -> 73.12 МБ
Я получил эти статистические данные дампа кучи после 10 часов работы приложения. Но не смог определить, откуда создаются эти объекты Logger. Когда я открываю дерево ссылок в MAT, оно не указывает на классы приложения, большинство узлов ссылаются на специфичные для фреймворка классы.
В этом случае, как подойти к этой проблеме и как определить, почему создается такое количество экземпляров логгера и почему они занимают столько памяти?
Мое приложение определяет все логи как private final, и все мои классы приложения аннотированы @Component. Таким образом, в идеале должен создаваться только один экземпляр Logger на класс.
Ответ или решение
Проблема с утечками памяти, связанная с библиотекой логирования Log4j2 в вашем приложении Spring Boot, может быть связана с несколькими факторами. Давайте разберем ваше описание и предложим стратегию для диагностики и решения этой проблемы.
Анализ ситуации
-
Объекты Logger: В вашем случае количество созданных объектов
Logger
составляет 982,392, что указывает на возможную утечку памяти. В идеале, как вы правильно заметили, при использовании модификатора доступаprivate final
все экземпляры логгеров должны создаваться только один раз на каждый класс. -
Сложность трассировки: Учитывая, что вы используете Spring Boot и огромное количество объектов указывает на фреймворк, а не на ваш код, это может быть признаком того, что логгеры создаются в результате неправильной конфигурации или особенностей инициализации контекста Spring.
Рекомендации по диагностике
-
Проверка конфигурации Log4j2:
- Убедитесь, что конфигурацию Log4j2 вы сделали корректно. Изучите файл конфигурации
log4j2.xml
илиlog4j2.properties
. Убедитесь, что не используется динамическое создание логгеров, или не включены пулы логирования, которые могут предлагать создание логгеров в каждом его вызове.
- Убедитесь, что конфигурацию Log4j2 вы сделали корректно. Изучите файл конфигурации
-
Профилирование:
- Используйте инструменты профилирования для мониторинга создания экземпляров
Logger
. Вы можете использовать такие инструменты, как VisualVM, JProfiler или YourKit для отслеживания объектов в памяти и их создания. - Обратите особое внимание на стек вызовов, когда
Logger
создается, чтобы выяснить, какой код его инициирует.
- Используйте инструменты профилирования для мониторинга создания экземпляров
-
Проверка зависимостей:
- Осмотрите ваши зависимости, особенно библиотеки, которые могут случайным образом инициализировать логгеры, такие как библиотеки, интегрирующиеся с Spring (например, иногда сторонние библиотеки могут создавать свои собственные логгеры без вашего ведома).
-
Анализ кода:
- Проверьте все места в коде, где вы используете
Logger
. Убедитесь, что логгер создается корректно и нет случайного создания локальных экземпляров.
- Проверьте все места в коде, где вы используете
-
Обновление до последней версии:
- Убедитесь, что используете последнюю стабильную версию Log4j2 и Spring Boot, так как в последних версиях могут содержаться исправления, касающиеся утечек памяти.
Решение проблемы
-
Устранение дублирования Logger:
- Внедрите единую службу логирования, которая будет обеспечивать создание и управление логгерами в одном месте, и не забудьте использовать паттерн проектирования “Singleton”.
-
Оптимизация кода:
- Пересмотрите все классы и методы. Рассмотрите возможность удаления явных инициализаций логгеров там, где это не требуется.
-
Использовать AOP для логирования:
- Рассмотрите внедрение аспектно-ориентированного программирования (AOP) для обработки логирования, что может помочь в оптимизации путей создания логгеров.
-
Кэширование Logger:
- Вы можете реализовать кэширование логгеров в статических мапах, чтобы избежать перезаписи.
Надеюсь, что эти рекомендации помогут вам диагностировать и устранить проблему утечек памяти с объектами Logger
в вашем приложении. Не забудьте сделать резервные копии конфигураций и тщательно тестировать изменения в изолированной среде перед развертыванием на продакшене.