
Команда Spring АйО провела анализ проблем с памятью, возникших после перехода с JDK 8 на JDK 17. Обновление прошло успешно на этапе разработки и QA, однако в продакшене система начала давать сбои через несколько часов после развертывания.
- Увеличение потребления памяти в 4 раза
- Контейнеры начали перезапускаться из-за OOMKill
- Рост количества потоков до 1600+
- Проблемы с нативной памятью, увеличившейся с 800 MB до 3.6 GB
Анализ причин возникновения проблем
При миграции на JDK 17 возникли три ключевые проблемы, усугубленные контейнеризацией:
- Неверное определение CPU: JVM неправильно определила количество доступных процессоров, что привело к увеличению числа потоков.
- Фрагментация malloc-арен: Из-за увеличения числа потоков glibc создала слишком много арен памяти.
- Накладные расходы G1GC: Переход на новый сборщик мусора увеличил потребление нативной памяти.
Решения и рекомендации
Для устранения проблем были предложены следующие меры:
| Решение | Описание |
|---|---|
| -XX:ActiveProcessorCount=2 | Явно задать количество процессоров для JVM. |
| export MALLOC_ARENA_MAX=2 | Ограничить количество malloc-арен glibc. |
| Настройка G1GC или переход на ParallelGC | Оптимизация сборки мусора для снижения накладных расходов. |
После внедрения этих решений, использование памяти стабилизировалось на уровне 65-70%. Команда также внедрила Native Memory Tracking (NMT) для более детального мониторинга нативной памяти и установила алерты для отслеживания роста числа потоков.
Опыт перехода на JDK 17 стал важным уроком, подчеркнув необходимость внимательного подхода к обновлениям JVM и мониторингу потребления памяти в контейнеризованных средах.