Если вы столкнулись с ошибкой PermGen error в Minecraft или при работе с Java-вебприложениями, то вы попали по адресу. В этом посте мы разберём, что такое PermGen, почему возникает ошибка OutOfMemoryError: PermGen space, как её диагностировать и, главное, как избавиться от неё раз и навсегда. Приготовьтесь к яркому путешествию в мир Java-памяти, class loader-ов и хитростей Tomcat!


Что такое PermGen и почему она важна

PermGen (Permanent Generation) — это специальная область памяти в JVM, где хранятся описания классов Java и метаданные. Представьте PermGen как шкафчик с костюмами для ваших Java-классов: каждый раз, когда веб-приложение запускается или перезапускается, туда загружаются новые костюмы. Если шкафчик переполнен, JVM выдает ошибку OutOfMemoryError: PermGen space — и тут начинается веселье.

В Java 8 PermGen заменили на Metaspace, который динамически расширяется, но проблема с утечками памяти и переполнением осталась актуальной, особенно для серверов с Tomcat и веб-приложениями.


Почему возникает ошибка PermGen error в Minecraft и веб-приложениях

Основные причины:

  • Перезапуск веб-приложения без перезапуска сервера. При этом старые классы не выгружаются из PermGen, а новые загружаются поверх.
  • Утечки памяти из-за неправильной работы class loader-ов. Если на классы ссылаются объекты вне веб-приложения, сборщик мусора не может их убрать.
  • Неостановленные потоки (Threads), запущенные из веб-приложения, которые продолжают держать ссылки на class loader.
  • ThreadLocal-переменные, которые не очищаются, создавая цепочку ссылок и блокируя выгрузку классов.

Как понять, что у вас именно PermGen error

Признаки:

  • В логах сервера появляется ошибка java.lang.OutOfMemoryError: PermGen space.
  • Сервер Minecraft или веб-приложение падает с сообщением о нехватке PermGen памяти.
  • При перезапуске приложения ошибка повторяется всё чаще.
  • В логах Tomcat можно увидеть предупреждения о неостановленных потоках или ThreadLocal.

Практические шаги для решения PermGen error

1. Увеличьте размер PermGen памяти

Добавьте в параметры JVM:

-XX:MaxPermSize=256m

Это отсрочит проблему, но не решит её полностью.

2. Используйте правильный сборщик мусора

Для Java 7 + Tomcat 7 рекомендуется включить:

-XX:+UseConcMarkSweepGC
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenSweepingEnabled

Эти опции помогут JVM лучше выгружать классы из PermGen.

3. Остановите и очистите неостановленные потоки

В логах Tomcat ищите сообщения типа:

SEVERE: The web application [...] appears to have started a thread named [...] but has failed to stop it.

Найдите и исправьте код, который не останавливает потоки при остановке приложения. Например, вызовите Thread#interrupt() или установите флаг остановки.

4. Очистите ThreadLocal-переменные

ThreadLocal — это ловушка для утечек, если не вызывать remove() после использования. Проверьте, что для каждого put() вызывается remove().

5. Используйте встроенные средства Tomcat

  • Кнопка Find leaks в Tomcat Manager Application покажет подозрительные утечки.
  • Включите в server.xml слушатель JreMemoryLeakPreventionListener с параметром AWTThreadProtection=true для защиты от специфических утечек.

6. Анализируйте память с помощью VisualVM

VisualVM — бесплатный профайлер из JDK, который поможет:

  • Сделать heap dump.
  • Выполнить OQL-запросы для поиска WebappClassLoader, который не выгружается.
  • Найти ссылки, мешающие сборщику мусора.

Пример OQL-запроса:

select x from org.apache.catalina.loader.WebappClassLoader x

Таблица основных JVM опций для борьбы с PermGen error

Опция Назначение Рекомендуется для
-XX:MaxPermSize=256m Увеличение максимального размера PermGen Все JVM до Java 8
-XX:+UseConcMarkSweepGC Включение CMS сборщика мусора Java 7 + Tomcat 7
-XX:+CMSClassUnloadingEnabled Позволяет выгружать классы при CMS сборке мусора Java 7 + Tomcat 7
-XX:+CMSPermGenSweepingEnabled Оптимизация очистки PermGen Java 7 + Tomcat 7
JreMemoryLeakPreventionListener Защита от известных утечек памяти в Tomcat Tomcat серверы
AWTThreadProtection=true Защита от утечек потоков AWT Tomcat серверы

Как избежать PermGen error в будущем

  • Перезапускайте сервер, а не только веб-приложения, если возможно.
  • Следите за корректным завершением потоков и очисткой ThreadLocal.
  • Используйте современные версии Java (Java 8 и выше), где PermGen заменён на Metaspace.
  • Регулярно анализируйте логи и память с помощью инструментов профилирования.
  • Настраивайте JVM параметры под нагрузку и особенности вашего приложения.

Пример из жизни: как я победил PermGen error

В одном из проектов сервер Minecraft регулярно падал с ошибкой PermGen. Анализ логов показал, что поток AWT-Windows не останавливается. Добавил в server.xml Tomcat параметр:

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" AWTThreadProtection="true" />

Проблема исчезла! Также проверил код на наличие ThreadLocal без вызова remove() — исправил. После этого сервер работал стабильно без падений.


Итог

PermGen error — это вызов для разработчика и администратора. Понимание архитектуры JVM, class loader-ов и правильная настройка JVM помогут вам избавиться от этой ошибки и сделать ваш Minecraft-сервер или веб-приложение стабильным и быстрым.


Полезные ссылки


Пусть ваш сервер будет крепким, а память — чистой! Если PermGen error снова постучится в дверь — вы теперь знаете, как с ним справиться.