Недавно я столкнулся с этой ошибкой в своем веб-приложении:
java.lang.OutOfMemoryError: PermGen space
Это типичное приложение Hibernate / JPA + IceFaces / JSF, работающее на Tomcat 6 и JDK 1.6. По-видимому, это может произойти после повторного развертывания приложения несколько раз.
Что вызывает это и что можно сделать, чтобы этого избежать? Как мне решить проблему?
А как вы с этим столкнулись?
используйте JDK 1.8: þ добро пожаловать в MetaSpace
Я боролся с этим часами, но у меня нет хороших новостей. См. Мой связанный с этим вопрос: stackoverflow.com/questions/1996088/… У вас все еще может быть утечка памяти, например. классы не собираются сборщиком мусора, потому что ваш WebAppClassLoader не является сборщиком мусора (у него есть внешняя ссылка, которая не очищается). увеличение PermGen только задержит OutOfMemoryError, а разрешение сборки мусора классов является предварительным условием, но не приведет к классам сборки мусора, если их загрузчик классов все еще имеет ссылки на него.
При использовании Windows следуйте этим инструкциям вместо того, чтобы пытаться вручную устанавливать флаги в файлах конфигурации. Это правильно устанавливает значения в реестре, которые будут вызываться Tomcat во время выполнения. stackoverflow.com/questions/21104340/…


Решением было добавить эти флаги в командную строку JVM при запуске Tomcat:
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
Вы можете сделать это, выключив службу tomcat, затем зайдя в каталог Tomcat / bin и запустив tomcat6w.exe. На вкладке «Java» добавьте аргументы в поле «Параметры Java». Нажмите «ОК», а затем перезапустите службу.
Если вы получили ошибку указанная служба не существует как установленная служба, запустите:
tomcat6w //ES//servicename
где наименование услуги - имя сервера, как показано в services.msc
Источник: комментарий orx к Гибкие ответы Эрика.
В статье ниже также предлагаются -XX: + UseConcMarkSweepGC и -XX: MaxPermSize = 128m. my.opera.com/karmazilla/blog/2007/03/13/…
-XX: + CMSPermGenSweepingEnabled Этот параметр снижает производительность. Каждый запрос в наших системах занимает в три раза больше времени, чем обычно. Используйте с осторожностью.
у меня сработало - спасибо - я делаю это на Ubuntu 10.10 с Tomcat6 - я создал новый файл: /usr/share/tomcat6/bin/setenv.sh и добавил к нему следующую строку: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- перезапуск tomcat с использованием: sudo /etc/init.d/tomcat6 start
При запуске tomcat 6.0.29 из моего файла журнала catalina.out: «Пожалуйста, используйте CMSClassUnloadingEnabled вместо CMSPermGenSweepingEnabled в будущем»
На tomcat 5.5 в Ubuntu я изменил /etc/default/tomcat5.5 следующим образом: JAVA_OPTS = "- Djava.awt.headless = true -Xms128M -Xmx512M -XX: + CMSClassUnloadingEnabled -XX: MaxPermSize = 128m"
Я не могу открыть tomcat6w.exe :( Он говорит: «Указанная служба не существует как установленная. Невозможно открыть службу tomcat6». Может ли кто-нибудь помочь мне в этом?
Прежде всего, было бы здорово объяснить, что на самом деле делают эти флаги. ИМХО недостаточно просто сказать: «сделай это и наслаждайся».
Во-вторых, если ваше приложение действительно пропускает загрузчик классов, то есть оставляет где-то объект или класс, загруженный загрузчиком классов приложения, даже после отмены развертывания, эти флаги не помогут. Я написал сообщение в блоге об этом и других предложениях в этой теме: plumbr.eu/blog/busting-permgen-myths
-XX: + CMSClassUnloadingEnabled и -XX: + CMSPermGenSweepingEnabled неприменимы в java 1.7, см. связь
@lolotron, с Java OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode) ... запущенным java -XX:+PrintFlagsFinal -version ... возвращенный список флагов включает CMSClassUnloadingEnabled.
@lolotron вульгарно пытается установить его на tomcat 7 на «Java HotSpot (TM) Server VM (сборка 24.45-b08, смешанный режим)», он работает нормально (ошибок OutOfMemory больше нет).
Чтобы узнать больше о флагах - stackoverflow.com/questions/3334911/…
Немного устарело, как этот поток, но вот документация от Oracle: oracle.com/technetwork/java/…
Я могу сделать это на tomcat 7: добавить эту строку в setenv.sh [JAVA_OPTS = "- Xms256m -Xmx512m -XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled"]? это сработает?
что сработало для меня в окнах: создал файл ${tomcat-folder}\bin\setenv.bat, содержащий одну строку: set JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m
Правильным решением является устранение проблем с утечкой памяти и их устранение. Если вы зарегистрировали драйверы JDBC, отмените их регистрацию. Вы можете использовать javax.servlet.ServletContextListener. Я опубликовал решение ниже с образцом кода для отмены регистрации драйверов / потоков / т. Д.
Что, если я использую WebLogic?
Обратите внимание, что CMSClassUnloadingEnabled по умолчанию включен.
По какой-либо причине они не включены по умолчанию?
В качестве альтернативы вы можете переключиться на JRockit, который обрабатывает permgen иначе, чем sun jvm. Как правило, он также имеет лучшую производительность.
http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html
Хотя у JRockit действительно нет PermGen, но в долгосрочной перспективе это не поможет. Вместо этого вы получите java.lang.OutOfMemoryError: There is insufficient native memory.
jrockit решил эту проблему и для меня; однако я заметил, что время перезапуска сервлетов было намного хуже, поэтому, хотя это было лучше в производстве, это было своего рода тормозом в разработке.
Используйте параметр командной строки -XX:MaxPermSize=128m для Sun JVM (очевидно, заменяя 128 на любой размер, который вам нужен).
Единственная проблема в том, что вы просто откладываете неизбежное - в какой-то момент у вас тоже закончится запас места. Это отличное прагматичное решение, но оно не решает его навсегда.
то же самое происходит в Eclipse, и каждый раз, когда у вас много динамической загрузки классов. загрузчики классов не выбрасываются и живут в постоянном поколении вечно
У меня заканчивались PermGen при выполнении особенно большого задания Hudson ... это исправило это для меня.
@TimHowland, это может быть постоянное исправление, если основная причина не в утечке загрузчика классов, а в слишком большом количестве классов / статических данных в вашем веб-приложении.
получил ту же проблему, что и HDave, при сборке jenkins / hudson из исходного кода.
Ошибки PermGen сервера приложений, возникающие после нескольких развертываний, скорее всего, вызваны ссылками, содержащимися в контейнере в загрузчики классов ваших старых приложений. Например, использование настраиваемого класса уровня журнала приведет к тому, что ссылки будут храниться загрузчиком классов сервера приложений. Вы можете обнаружить эти утечки между загрузчиками классов, используя современные (JDK6 +) инструменты анализа JVM, такие как jmap и jhat, чтобы посмотреть, какие классы продолжают храниться в вашем приложении, а также изменив или исключив их использование. Обычно подозреваемыми являются базы данных, регистраторы и другие библиотеки уровня базовой платформы.
См. Утечки из загрузчика классов: ужасное исключение "java.lang.OutOfMemoryError: PermGen space" и особенно его последующий пост.
Это единственно верное решение проблемы, которое в некоторых случаях слишком сложно реализовать.
Еще один очень хороший источник - people.apache.org/~markt/presentations/… (из диспетчера выпуска Tomcat !!).
Хотя теоретически это может дать ответ на вопрос, было бы предпочтительнее включает сюда основные части ответа и предоставляет ссылку для справки.
Попробуйте -XX:MaxPermSize=256m, и если проблема не исчезнет, попробуйте -XX:MaxPermSize=512m
и если он все еще сохраняется, попробуйте XX:MaxPermSize=1024m :)
и если он все еще сохраняется, попробуйте XX: MaxPermSize = 2048m :)
И если это все еще не исчезнет, пересмотрите свое приложение !! Или попробуйте XX: MaxPermSize = 4096m :)
вы также можете попробовать 8192 м, но это немного перебор
В самом деле, перебор - 640 КБ должно хватить любому!
давайте посмотрим ... 2012 ppl скажем 1024, 2013 - 2048, 2014 это было 4096 и 2015 приходит на 8192. Теперь просто потратьте эти 100 долларов на ваш 16384.
Ну, у меня была такая же проблема, поэтому все, что я сделал, это XX: MaxPermSize = 131072m :)
Конфигурация памяти зависит от характера вашего приложения.
Что делаешь?
Какой объем транзакций предварительно обработан?
Сколько данных вы загружаете?
и Т. Д.
и Т. Д.
так далее
Возможно, вы могли бы профилировать свое приложение и начать очистку некоторых модулей из вашего приложения.
Apparently this can occur after redeploying an application a few times
Tomcat имеет горячее развертывание, но потребляет память. Попробуйте время от времени перезапускать контейнер. Также вам необходимо знать объем памяти, необходимый для работы в производственном режиме, это хорошее время для исследования.
Лучше попробуйте -XX:MaxPermSize=128M, а не -XX:MaxPermGen=128M.
Я не могу сказать точно, как используется этот пул памяти, но это связано с количеством классов, загруженных в JVM. (Таким образом, включение выгрузки классов для tomcat может решить проблему.) Если ваши приложения генерируют и компилируют классы на ходу, скорее всего, потребуется пул памяти большего размера, чем по умолчанию.
Фактически, это только отложит OOMError. См. Ответ ниже, начатый анонимом, с двумя ссылками на блог frankkieviet.
Эти параметры объясняются здесь: oracle.com/technetwork/java/javase/tech/…
У меня есть комбинация Hibernate + Eclipse RCP, я пробовал использовать -XX:MaxPermSize=512m и -XX:PermSize=512m, и, похоже, у меня это работает.
Установите -XX:PermSize=64m -XX:MaxPermSize=128m. Позже вы также можете попробовать увеличить MaxPermSize. Надеюсь, это сработает. У меня то же самое. Установка только MaxPermSize у меня не сработала.
Говорят, что последняя версия Tomcat (6.0.28 или 6.0.29) лучше справляется с задачей повторного развертывания сервлетов много.
«Они» неверны, потому что я использую 6.0.29, и у меня такая же проблема даже после установки всех параметров. Как сказал Тим Хауленд выше, эти варианты только откладывают неизбежное. Они позволяют мне повторно развертывать 3 раза, прежде чем выдать ошибку, вместо того, чтобы каждый раз развертывать заново.
Если вы получаете это в Eclipse IDE, даже после установки параметров
--launcher.XXMaxPermSize, -XX:MaxPermSize и т. д., Тем не менее, если вы получаете ту же ошибку, скорее всего, eclipse использует версию JRE с ошибками, которая была бы установлена некоторыми сторонними приложениями и настроена по умолчанию. Эти версии с ошибками не принимают параметры PermSize, поэтому независимо от того, что вы установили, вы все равно продолжаете получать эти ошибки памяти. Итак, в свой eclipse.ini добавьте следующие параметры:
-vm <path to the right JRE directory>/<name of javaw executable>
Также убедитесь, что вы установили JRE по умолчанию в настройках в eclipse на правильную версию java.
Единственный способ, который сработал для меня, - это JRockit JVM. У меня MyEclipse 8.6.
В куче JVM хранятся все объекты, созданные запущенной программой Java. Java использует оператор new для создания объектов, а память для новых объектов выделяется в куче во время выполнения. Сборка мусора - это механизм автоматического освобождения памяти, содержащейся объектами, на которые программа больше не ссылается.
У меня возникла проблема, о которой мы здесь говорим, мой сценарий - eclipse-helios + tomcat + jsf, а вы делали развертывание простого приложения на tomcat. Я показывал здесь ту же проблему, решил ее следующим образом.
В eclipse перейдите на вкладку серверы, дважды щелкните зарегистрированный сервер в моем случае tomcat 7.0, он откроет мой файловый сервер Общая регистрационная информация. В разделе "Общая информация" щелкните ссылку «Открытая конфигурация запуска», это откроет выполнение параметров сервера на вкладке «Аргументы» в аргументах виртуальной машины, добавленных в конце этих двух записей.
-XX: MaxPermSize = 512m
-XX: PermSize = 512m
и готово.
Я сталкиваюсь с той же проблемой, но, к сожалению, ни одно из предложенных решений не помогло мне. Проблема не возникла во время развертывания, и я также не выполнял горячих развертываний.
В моем случае проблема возникала каждый раз в одной и той же точке во время выполнения моего веб-приложения при подключении (через спящий режим) к базе данных.
Эта ссылка (также упомянутый ранее) действительно предоставил достаточно внутренних компонентов для решения проблемы. Перемещение драйвера jdbc- (mysql) из WEB-INF в папку jre / lib / ext /, похоже, решило проблему. Это не идеальное решение, поскольку для обновления до более новой JRE потребуется переустановить драйвер. Другой кандидат, который может вызвать аналогичные проблемы, - это log4j, поэтому вы также можете переместить его.
Если вы не хотите включать драйвер в jre / lib / ext, вы, вероятно, можете получить те же результаты, включив драйвер в путь к классам запуска вашего контейнера. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap. контейнер jar.Start
Также, если вы используете log4j в своем веб-приложении, проверьте этот абзац в log4j документация.
Похоже, что если вы используете PropertyConfigurator.configureAndWatch("log4j.properties"), вы вызываете утечку памяти при отмене развертывания веб-приложения.
Я столкнулся с этой проблемой при развертывании и отмене развертывания сложного веб-приложения, и подумал, что добавлю объяснение и свое решение.
Когда я развертываю приложение на Apache Tomcat, для этого приложения создается новый ClassLoader. Затем ClassLoader используется для загрузки всех классов приложения, и при отмене развертывания все должно удаляться. Однако на самом деле все не так просто.
Один или несколько классов, созданных во время жизни веб-приложения, содержат статическую ссылку, которая где-то вдоль линии ссылается на ClassLoader. Поскольку ссылка изначально статична, никакая сборка мусора не очистит эту ссылку - ClassLoader и все загруженные классы останутся здесь.
И после пары повторных развертываний мы обнаруживаем OutOfMemoryError.
Теперь это стало довольно серьезной проблемой. Я мог бы убедиться, что Tomcat перезапускается после каждого повторного развертывания, но это приводит к отключению всего сервера, а не только повторного развертывания приложения, что часто невозможно.
Поэтому вместо этого я собрал решение в коде, которое работает на Apache Tomcat 6.0. Я не тестировал другие серверы приложений и должен подчеркнуть, что очень вероятно, что это не будет работать без изменений на любом другом сервере приложений.
Я также хотел бы сказать, что лично я ненавижу этот код и этот никто не должен использовать это как «быстрое решение», если существующий код можно изменить для использования надлежащих методов завершения работы и очистки.. Единственный раз, когда это следует использовать, - это если есть внешняя библиотека, от которой зависит ваш код (в моем случае это был клиент RADIUS), которая не предоставляет средств для очистки своих собственных статических ссылок.
Во всяком случае, продолжайте с кодом. Это должно быть вызвано в точке, где приложение отключается - например, метод уничтожения сервлета или (лучший подход) метод contextDestroyed ServletContextListener.
//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
try {
classLoaderClassesField = clazz.getDeclaredField("classes");
} catch (Exception exception) {
//do nothing
}
clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);
List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));
for (Object o : classes) {
Class c = (Class)o;
//Make sure you identify only the packages that are holding references to the classloader.
//Allowing this code to clear all static references will result in all sorts
//of horrible things (like java segfaulting).
if (c.getName().startsWith("com.whatever")) {
//Kill any static references within all these classes.
for (Field f : c.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())
&& !Modifier.isFinal(f.getModifiers())
&& !f.getType().isPrimitive()) {
try {
f.setAccessible(true);
f.set(null, null);
} catch (Exception exception) {
//Log the exception
}
}
}
}
}
classes.clear();
Я знаю, что прошло более 8 лет с тех пор, как я написал это, но где-то между тем и сейчас я нашел более глубокую первопричину и решение. Дело в том, что, хотя все классы в веб-приложении принадлежат загрузчику классов контекста, поток, который вызывает обратный вызов запуска и завершения работы, принадлежит родительскому загрузчику классов. Это означает, что если код завершения инициализирует локальную переменную потока, это приведет к тому, что родительский загрузчик классов в конечном итоге будет удерживать ссылку на контекстный загрузчик классов, что препятствует хорошей очистке.
К счастью, есть очень простое решение - переместить весь код, находящийся в настоящее время в методе выключения, в метод выполнения нового объекта Thread. Затем в методе выключения запустите этот поток и дождитесь его завершения. Код очистки будет выполняться идентично, но любые локальные переменные потока останутся привязанными к загрузчику классов контекста вместо утечки.
Я попробовал несколько ответов, и единственное, что в итоге сработало, - это конфигурация плагина компилятора в pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<fork>true</fork>
<meminitial>128m</meminitial>
<maxmem>512m</maxmem>
<source>1.6</source>
<target>1.6</target>
<!-- prevent PermGen space out of memory exception -->
<!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
</configuration>
</plugin>
надеюсь, что это поможет.
"argLine" не распознается maven-compiler-plugin 2.4. он поддерживает только compilerArgument, который дает ошибку: <compilerArgument> -XX: MaxPermSize = 256m </compilerArgument> [ERROR] Ошибка при выполнении javac, но не удалось проанализировать ошибку: javac: недопустимый флаг: -XX: MaxPermSize = 256m Usage : javac <параметры> <исходные файлы>
Если на этапе компиляции заканчивается permgen, установите <compilerArgument> в maven-compiler-plugin. Если у модульных тестов заканчивается permgen, установите <argLine> в maven-surefire-plugin
Обычная ошибка, которую делают люди, - это думать, что пространство кучи и пространство перманента одинаковы, что совсем не так. У вас может остаться много места в куче, но в permgen все равно может не хватить памяти.
Распространенной причиной OutofMemory в PermGen является ClassLoader. Всякий раз, когда класс загружается в JVM, все его метаданные, вместе с Classloader, хранятся в области PermGen, и они будут собираться мусором, когда Classloader, который их загрузил, будет готов к сборке мусора. В случае, если у Classloader есть утечка памяти, тогда все загруженные им классы останутся в памяти и вызовут выход permGen из памяти, если вы повторите это несколько раз. Классический пример - Java.lang.OutOfMemoryError: пространство PermGen в Tomcat.
Теперь есть два способа решить эту проблему:
1. Найдите причину утечки памяти или ее наличие.
2. Увеличьте размер PermGen Space с помощью параметров JVM -XX:MaxPermSize и -XX:PermSize.
Вы также можете проверить 2 Решение Java.lang.OutOfMemoryError в Java для получения дополнительных сведений.
Как передать параметр -XX:MaxPermSize and -XX:PermSize ?? Не могу найти catalina.bat. Моя версия tomcat - 5.5.26.
Как найти утечки памяти загрузчика классов? Вы рекомендуете какой-нибудь инструмент?
@amit для получения рекомендаций по инструментам, см. ответ на этот вопрос в вики-сообществе.
@Deckard заходит в каталог Tomcat / bin и запускает tomcat6w.exe. На вкладке «Java» добавьте аргументы в поле «Параметры Java». Нажмите "ОК".
Увеличение размера постоянного поколения или настройка параметров GC НЕ помогут, если у вас есть реальная утечка памяти. Если ваше приложение или какая-либо сторонняя библиотека, которую оно использует, вызывает утечку загрузчиков классов, единственное реальное и постоянное решение - найти эту утечку и исправить ее. Есть ряд инструментов, которые могут вам помочь, одним из последних является Plumbr, который только что выпустил новую версию с необходимыми возможностями.
Вы также можете решить эту проблему, выполнив:
rm -rf <tomcat-dir>/work/* <tomcat-dir>/temp/*
Очистка каталогов работай и темп заставляет Tomcat выполнять чистый запуск.
Я добавлен-XX: MaxPermSize = 128m (вы можете поэкспериментировать, что работает лучше всего) до Аргументы ВМ, поскольку я использую eclipse ide. В большинстве JVM PermSize по умолчанию находится в районе 64 МБ, которому не хватает памяти, если в проекте слишком много классов или огромное количество строк.
Для eclipse это также описано в отвечать.
ШАГ 1: дважды щелкните сервер tomcat на вкладке Серверы

ШАГ 2: Открыть запуск Conf и добавьте -XX: MaxPermSize = 128m в конец существующего Аргументы ВМ.

Спасибо за ваш лучший подробный ответ (Примечание: нажмите «Открыть конфигурацию запуска», чтобы открыть окно «Изменить конфигурацию» ... но я использовал следующие параметры: «-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled»
В текстовой области Java Options добавьте эту строку:
-XX:MaxPermSize=128m
Самый простой ответ в наши дни - использовать Java 8.
Он больше не резервирует память исключительно для пространства PermGen, позволяя памяти PermGen смешиваться с обычным пулом памяти.
Имейте в виду, что вам придется удалить все нестандартные параметры запуска JVM -XXPermGen...=..., если вы не хотите, чтобы Java 8 жаловалась, что они ничего не делают.
Здравствуйте, этот ответ уже был дан: stackoverflow.com/a/22897121/505893. Пожалуйста, удалите свой ответ для ясности. При необходимости вы можете улучшить ответ, который я упомянул. Спасибо ;)
@bluish Спасибо, что указали на это; однако этот ответ идет вразрез с разговором об исключениях OutOfMemoryExceptions и утечке метаданных. Также не упоминаются очень важные моменты удаления опции PermGen. Короче говоря, я не уверен, что буду улучшать ответ, а скорее переписываю его. Если бы это было просто быстрое исправление, я бы не колебался, но похоже, что это было бы намного больше, чем быстрое исправление, и я бы не хотел обидеть автора оригинала. Тем не менее, этот список ответов - собачий обед из беспорядка, и, возможно, лучше всего было бы убить мой пост.
Первое, что можно сделать, - это увеличить размер кучи постоянного поколения. Это невозможно сделать с помощью обычных аргументов JVM –Xms (установить начальный размер кучи) и –Xmx (установить максимальный размер кучи), поскольку, как уже упоминалось, пространство кучи постоянного поколения полностью отделено от обычного пространства кучи Java, и эти аргументы устанавливают пространство для этого обычного пространства кучи Java. Однако есть аналогичные аргументы, которые можно использовать (по крайней мере, с jvms Sun / OpenJDK), чтобы увеличить размер кучи постоянного поколения:
-XX:MaxPermSize=128m
По умолчанию 64 м.
Еще один способ позаботиться об этом навсегда - разрешить выгрузку классов, чтобы ваш PermGen никогда не заканчивался:
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
Подобные вещи в прошлом творили для меня волшебство. Одна вещь, однако, при их использовании возникает значительный компромисс в производительности, поскольку перманентная очистка будет делать как дополнительные 2 запроса на каждый ваш запрос или что-то в этом роде. Вам нужно будет найти баланс между использованием и компромиссами.
Вы можете найти подробную информацию об этой ошибке.
http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html
Отличный пост @faisalbhagat faisalbhagat.blogspot.com/2014/09/…
Вариант 2 хорош, но учтите, что его не следует использовать в производственной среде. Как правило, лучше всего оставить это только для сред разработки. Однако PermGen удален с Java 8 openjdk.java.net/jeps/122
Ошибка пространства Perm gen возникает из-за использования большого пространства, а не пространства, предоставленного jvm для выполнения кода.
Лучшее решение этой проблемы в операционных системах UNIX - изменить некоторую конфигурацию файла bash. Следующие шаги решают проблему.
Запустите команду gedit .bashrc на терминале.
Создайте переменную JAVA_OTPS со следующим значением:
export JAVA_OPTS = "-XX:PermSize=256m -XX:MaxPermSize=512m"
Сохраните файл bash. Запустите команду exec bash на терминале. Перезагрузите сервер.
Я надеюсь, что этот подход сработает для вашей проблемы. Если вы используете версию Java ниже 8, эта проблема иногда возникает. Но если вы используете Java 8, проблем никогда не возникает.
У меня была аналогичная проблема. Мой - это JDK 7 + Maven 3.0.2 + Struts 2.0 + проект на основе внедрения зависимостей Google GUICE.
Всякий раз, когда я пытался запустить команду mvn clean package, она показывала следующую ошибку, и происходило «СТРОИТЬ ОТКАЗ»
org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; nested exception is java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Caused by: java.lang.OutOfMemoryError: PermGen space
Я попробовал все вышеперечисленные полезные советы и приемы, но, к сожалению, ни один из них не помог мне. То, что у меня сработало, описано ниже шаг за шагом: =>
<artifactId>maven-surefire-plugin</artifactId><configuration>, а затем подэлемент <argLine>, в котором передайте -Xmx512m -XX:MaxPermSize=256m, как показано ниже =><configuration>
<argLine>-Xmx512m -XX:MaxPermSize=256m</argLine>
</configuration>
Надеюсь, это поможет, удачного программирования :)
Первый шаг в таком случае - проверить, разрешено ли сборщику мусора выгружать классы из PermGen. Стандартная JVM в этом отношении довольно консервативна - классы рождены, чтобы жить вечно. Таким образом, после загрузки классы остаются в памяти, даже если их больше не использует код. Это может стать проблемой, если приложение динамически создает множество классов, и сгенерированные классы не нужны в течение более длительного периода времени. В таком случае может быть полезно разрешить JVM выгружать определения классов. Этого можно добиться, добавив в сценарии запуска всего один параметр конфигурации:
-XX:+CMSClassUnloadingEnabled
По умолчанию для этого параметра установлено значение false, поэтому для включения этого параметра необходимо явно установить следующий параметр в параметрах Java. Если вы включите CMSClassUnloadingEnabled, GC также очистит PermGen и удалит классы, которые больше не используются. Имейте в виду, что этот параметр будет работать только в том случае, если UseConcMarkSweepGC также включен с помощью параметра ниже. Поэтому при запуске ParallelGC или, не дай бог, Serial GC, убедитесь, что вы установили свой GC на CMS, указав:
-XX:+UseConcMarkSweepGC
Пробел java.lang.OutOfMemoryError: PermGen указывает на то, что область памяти постоянного поколения исчерпана.
Любым Java-приложениям разрешено использовать ограниченный объем памяти. Точный объем памяти, который может использовать ваше конкретное приложение, указывается при запуске приложения.
Память Java разделена на разные области, которые можно увидеть на следующем изображении:
Metaspace: рождается новое пространство памяти
JDK 8 HotSpot JVM теперь использует внутреннюю память для представления метаданных класса и называется Metaspace; похож на Oracle JRockit и IBM JVM.
Хорошая новость заключается в том, что это означает, что проблем с пространством памяти java.lang.OutOfMemoryError: PermGen больше не будет, и вам больше не потребуется настраивать и контролировать это пространство памяти с помощью Java_8_Download или выше.
Назначение Tomcat дополнительной памяти НЕ является правильным решением.
Правильное решение - выполнить очистку после уничтожения и воссоздания контекста (горячее развертывание). Решение - остановить утечку памяти.
Если ваш Tomcat / Webapp Server сообщает вам, что не удалось отменить регистрацию драйверов (JDBC), отмените их регистрацию. Это остановит утечку памяти.
Вы можете создать ServletContextListener и настроить его в своем web.xml. Вот пример ServletContextListener:
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Logger;
import com.mysql.jdbc.AbandonedConnectionCleanupThread;
/**
*
* @author alejandro.tkachuk / calculistik.com
*
*/
public class AppContextListener implements ServletContextListener {
private static final Logger logger = Logger.getLogger(AppContextListener.class);
@Override
public void contextInitialized(ServletContextEvent arg0) {
logger.info("AppContextListener started");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
logger.info("AppContextListener destroyed");
// manually unregister the JDBC drivers
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.info(String.format("Unregistering jdbc driver: %s", driver));
} catch (SQLException e) {
logger.info(String.format("Error unregistering driver %s", driver), e);
}
}
// manually shutdown clean up threads
try {
AbandonedConnectionCleanupThread.shutdown();
logger.info("Shutting down AbandonedConnectionCleanupThread");
} catch (InterruptedException e) {
logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
e.printStackTrace();
}
}
}
И здесь вы настраиваете его в своем web.xml:
<listener>
<listener-class>
com.calculistik.mediweb.context.AppContextListener
</listener-class>
</listener>
Я получил эту ошибку при добавлении отображать taglib. Удаление так также решило ошибку. Почему так?