Работа с ошибкой "java.lang.OutOfMemoryError: PermGen space" - PullRequest
1207 голосов
/ 18 сентября 2008

Недавно я столкнулся с этой ошибкой в ​​моем веб-приложении:

java.lang.OutOfMemoryError: PermGen space

Это типичное приложение Hibernate / JPA + IceFaces / JSF, работающее на Tomcat 6 и JDK 1.6. По-видимому, это может произойти после повторного развертывания приложения несколько раз.

Что вызывает это и что можно сделать, чтобы этого избежать? Как мне решить проблему?

Ответы [ 32 ]

560 голосов
/ 18 сентября 2008

Решением было добавить эти флаги в командную строку JVM при запуске Tomcat:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Это можно сделать, выключив службу tomcat, затем перейдя в каталог Tomcat / bin и запустив tomcat6w.exe. На вкладке «Java» добавьте аргументы в поле «Параметры Java». Нажмите «ОК» и перезапустите сервис.

Если вы получаете сообщение об ошибке указанная служба не существует как установленная служба , вам следует запустить:

tomcat6w //ES//servicename

, где имя_службы - это имя сервера в соответствии с services.msc

Источник: комментарий orx к Быстрые ответы Эрика .

250 голосов
/ 07 мая 2009

Вам лучше попробовать -XX:MaxPermSize=128M, а не -XX:MaxPermGen=128M.

Я не могу сказать точное использование этого пула памяти, но это связано с количеством классов, загруженных в JVM. (Таким образом, разрешение выгрузки классов для tomcat может решить эту проблему.) Если ваши приложения генерируют и компилируют классы на ходу, более вероятно, что потребуется пул памяти больше, чем по умолчанию.

152 голосов
/ 05 декабря 2008

Сервер приложений Ошибки PermGen, возникающие после нескольких развертываний, вероятнее всего вызваны ссылками, содержащимися в контейнере на загрузчики классов ваших старых приложений. Например, использование пользовательского класса уровня журнала приведет к тому, что ссылки будут храниться загрузчиком классов сервера приложений. Вы можете обнаружить эти утечки между классами загрузчиков, используя современные (JDK6 +) инструменты анализа JVM, такие как jmap и jhat, чтобы посмотреть, какие классы по-прежнему хранятся в вашем приложении, и изменить или исключить их использование. Обычно подозреваемыми являются базы данных, средства ведения журнала и другие библиотеки базового уровня.

См. Утечки в Classloader: страшное исключение "java.lang.OutOfMemoryError: PermGen space" , и особенно его следующий пост .

67 голосов
/ 04 января 2012

Распространенные ошибки, которые совершают люди, - это думать, что пространство кучи и пространство permgen одно и то же, что вовсе не так. У вас может быть много свободного места в куче, но все равно может не хватить памяти в permgen.

Распространенными причинами OutofMemory в PermGen является ClassLoader. Всякий раз, когда класс загружается в JVM, все его метаданные вместе с Classloader хранятся в области PermGen, и они будут собираться мусором, когда загрузчик Classloader, который их загрузил, готов для сбора мусора. В случае, если Classloader имеет утечку памяти, все загруженные им классы останутся в памяти и вызовут излишнюю память permGen, если вы повторите это пару раз. Классическим примером является Java.lang.OutOfMemoryError: PermGen Space в Tomcat .

Теперь есть два способа решить эту проблему:
1. Найдите причину утечки памяти или утечки памяти.
2. Увеличьте размер пространства PermGen с помощью параметров JVM -XX:MaxPermSize и -XX:PermSize.

Вы также можете проверить 2 Решение Java.lang.OutOfMemoryError в Java для получения более подробной информации.

40 голосов
/ 18 сентября 2008

Используйте параметр командной строки -XX:MaxPermSize=128m для Sun JVM (очевидно, заменяя 128 на любой нужный вам размер).

36 голосов
/ 12 марта 2009

Попробуйте -XX:MaxPermSize=256m и, если оно не исчезнет, ​​попробуйте -XX:MaxPermSize=512m

26 голосов
/ 03 марта 2013

I добавлено -XX: MaxPermSize = 128m (вы можете поэкспериментировать, что работает лучше всего) к Аргументы VM , поскольку я использую Eclipse Ide. В большинстве JVM значение PermSize по умолчанию составляет около 64MB , что заканчивается из-за слишком большого количества классов или огромного числа строк в проекте.

Для затмения это также описано в ответ .

ШАГ 1 : Двойной щелчок на сервере Tomcat в Серверы Вкладка

enter image description here

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

enter image description here

22 голосов
/ 09 июня 2011

Я пытался решить эту проблему, развернув и развернув сложное веб-приложение, и решил добавить объяснение и свое решение.

При развертывании приложения в 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();
15 голосов
/ 03 сентября 2014

1) Увеличение объема памяти PermGen

Первое, что можно сделать, - это увеличить размер кучи постоянного поколения. Это невозможно сделать с помощью обычных аргументов JVM –Xms (установить начальный размер кучи) и –Xmx (установить максимальный размер кучи), поскольку, как уже упоминалось, пространство кучи постоянного поколения полностью отделено от обычного пространства кучи Java, и эти аргументы устанавливают пространство для этого обычного пространства кучи Java. Однако есть аналогичные аргументы, которые можно использовать (по крайней мере для jvms Sun / OpenJDK), чтобы увеличить размер кучи постоянного поколения:

 -XX:MaxPermSize=128m

По умолчанию 64 м.

2) Включить подметание

Еще один способ позаботиться об этом - разрешить выгрузку классов, чтобы у вашего PermGen никогда не заканчивалось:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Такие вещи работали для меня магией в прошлом. Однако одно из них заключается в существенном компромиссе с производительностью при их использовании, так как развертки permgen будут делать как дополнительные 2 запроса на каждый запрос, который вы делаете, или что-то в этом роде. Вам необходимо сбалансировать использование с компромиссами.

Вы можете найти подробности этой ошибки.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html

15 голосов
/ 22 марта 2016

Пробел java.lang.OutOfMemoryError: PermGen указывает на то, что область постоянного поколения в памяти исчерпана.

Любым Java-приложениям разрешено использовать ограниченный объем памяти. Точный объем памяти, который может использовать ваше конкретное приложение, указывается при запуске приложения.

Память Java разделена на различные области, которые можно увидеть на следующем изображении:

enter image description here

Metaspace: рождается новое пространство памяти

JVK JSK 8 HotSpot теперь использует собственную память для представления метаданных класса и называется Metaspace; похож на Oracle JRockit и IBM JVM.

Хорошая новость заключается в том, что это означает, что больше не будет java.lang.OutOfMemoryError: PermGen проблем с пространством и вам больше не нужно настраивать и отслеживать это пространство памяти, используя Java_8_Download или выше.

...