Вопрос

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

java.lang.OutOfMemoryError:ПермГен пространство

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

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

Это было полезно?

Решение

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

tomcat6w //ES//servicename

где наименование услуги это имя сервера, как оно отображается в Services.msc.

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

Другие советы

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

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

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

Видеть Утечки загрузчика классов:ужасная "java.lang.OutOfMemoryError:Исключение пространства PermGen, и особенно его последующий пост.

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

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

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

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

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

Пытаться -XX:MaxPermSize=256m и если это сохранится, попробуйте -XX:MaxPermSize=512m

я добавлен -XX: MaxPermSize = 128m (вы можете поэкспериментировать, что работает лучше всего), чтобы Аргументы виртуальной машины поскольку я использую eclipse ide.В большинстве JVM Пермсизе по умолчанию вокруг 64 МБ которому не хватает памяти, если в проекте слишком много классов или огромное количество строк.

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

ШАГ 1 :Дважды щелкните сервер Tomcat по адресу Серверы Вкладка

enter image description here

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

enter image description here

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

Когда я развертываю приложение на Apache Tomcat, для этого приложения создается новый ClassLoader.Затем ClassLoader используется для загрузки всех классов приложения, и при отмене развертывания все должно исчезнуть.Однако на самом деле все не так просто.

Один или несколько классов, созданных во время существования веб-приложения, содержат статическую ссылку, которая где-то по ходу дела ссылается на ClassLoader.Поскольку ссылка изначально статична, никакая сборка мусора не очистит эту ссылку — ClassLoader и все загруженные им классы останутся здесь навсегда.

И после пары переразвертываний мы сталкиваемся с OutOfMemoryError.

Сейчас это стало достаточно серьезной проблемой.Я мог бы убедиться, что Tomcat перезапускается после каждого повторного развертывания, но при этом отключается весь сервер, а не только повторно развертываемое приложение, что часто невозможно.

Поэтому вместо этого я собрал решение в коде, которое работает на Apache Tomcat 6.0.Я не тестировал ни на каких других серверах приложений и должен подчеркнуть, что очень вероятно, что это не будет работать без изменений на любом другом сервере приложений..

Я также хотел бы сказать, что лично я ненавижу этот код, и что никто не должен использовать это как «быстрое решение», если существующий код можно изменить, чтобы использовать правильные методы завершения работы и очистки..Это следует использовать только в том случае, если существует внешняя библиотека, от которой зависит ваш код (в моем случае это был клиент RADIUS), которая не предоставляет средств для очистки своих собственных статических ссылок.

В любом случае, приступим к коду.Его следует вызывать в момент отмены развертывания приложения, например, методом Destroyed сервлета или (лучший подход) методом 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();

В качестве альтернативы вы можете переключиться на JRockit, который обрабатывает Permgen иначе, чем Sun JVM.Как правило, он также имеет лучшую производительность.

http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html

1) Увеличение размера памяти PermGen

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

 -XX:MaxPermSize=128m

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

2) Включить очистку

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

Вы можете найти подробную информацию об этой ошибке.

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

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

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

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

enter image description here

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

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

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

У меня возникла проблема, о которой мы здесь говорим: мой сценарий — eclipse-helios + tomcat + jsf, и вы делали развертывание простого приложения в tomcat.Я показывал здесь ту же проблему, решил ее следующим образом.

В затмении перейдите в серверы Дважды щелкните вкладку зарегистрированного сервера, в моем случае Tomcat 7.0, откроется общая регистрационная информация моего файлового сервера.На разделе "Общая информация" нажмите на ссылку «Открытая конфигурация запуска» , это открывает выполнение параметров сервера на вкладке «Аргументы» в аргументах виртуальной машины, добавленных в конце этих двух записей.

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

и готово.

Самый простой ответ на сегодняшний день — использовать Java 8.

Он больше не резервирует память исключительно для пространства PermGen, позволяя памяти PermGen смешиваться с обычным пулом памяти.

Имейте в виду, что вам придется удалить все нестандартные -XXPermGen...=... Параметры запуска JVM, если вы не хотите, чтобы Java 8 жаловалась, что они ничего не делают.

  1. Откройте Tomcat7W из каталога Bin's Bin's или монитора типа Tomcat в меню «Пуск» (окно с вкладками открывается с различной информацией об обслуживании).
  2. В текстовой области «Параметры Java» добавьте следующую строку:

    -XX:MaxPermSize=128m
    
  3. Установите начальный пул памяти на 1024 (необязательно).
  4. Установите максимальный пул памяти на 1024 (необязательно).
  5. Нажмите «ОК».
  6. Перезапустите службу Tomcat.

Ошибка Perm Gen Space возникает из-за использования большого пространства, а не из-за того, что jvm предоставил пространство для выполнения кода.Лучшее решение этой проблемы в операционных системах UNIX — изменить некоторую конфигурацию в файле bash.Следующие шаги решают проблему.

Команда Run gedit .bashrc на терминале.

Создавать JAVA_OTPS переменная со следующим значением:

export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"

Сохраните bash-файл.Запустите команду exec bash на терминале.Перезапустите сервер.

Я надеюсь, что этот подход поможет решить вашу проблему.Если вы используете версию Java ниже 8, эта проблема иногда возникает.Но если вы используете Java 8, проблема никогда не возникнет.

Увеличение размера постоянной генерации или настройка параметров GC НЕ помогут, если у вас есть реальная утечка памяти.Если ваше приложение или какая-либо сторонняя библиотека, которую оно использует, утечки загрузчиков классов, единственное реальное и постоянное решение — найти эту утечку и исправить ее.Существует ряд инструментов, которые могут вам помочь, один из последних — сантехника, которая только что выпустила новую версию с необходимыми возможностями.

Также, если вы используете log4j в своем веб-приложении, проверьте этот параграф в log4j. документация.

Кажется, что если вы используете PropertyConfigurator.configureAndWatch("log4j.properties"), вы вызываете утечку памяти при отмене развертывания веб-приложения.

У меня есть комбинация Hibernate+Eclipse RCP, пробовал использовать -XX:MaxPermSize=512m и -XX:PermSize=512m и, похоже, у меня это работает.

Набор -XX:PermSize=64m -XX:MaxPermSize=128m.Позже вы также можете попробовать увеличить MaxPermSize.Надеюсь, это сработает.То же самое работает и для меня.Только настройка MaxPermSize у меня не сработало.

Я попробовал несколько ответов, и единственное, что в конечном итоге помогло, — это конфигурация плагина компилятора в 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>

надеюсь, это поможет.

решил это и для меня;однако я заметил, что время перезапуска сервлетов было намного хуже, поэтому, хотя в производстве оно было лучше, это было своего рода тормозом в разработке.

Конфигурация памяти зависит от характера вашего приложения.

Что ты делаешь?

Какова сумма прецессированных транзакций?

Сколько данных вы загружаете?

и т. д.

и т. д.

и т. д.

Вероятно, вы могли бы профилировать свое приложение и начать очищать некоторые его модули.

По-видимому, это может произойти после повторного развертывания приложения несколько раз.

Tomcat имеет горячее развертывание, но оно потребляет память.Попробуйте время от времени перезапускать контейнер.Также вам нужно будет знать объем памяти, необходимый для работы в производственном режиме. Кажется, сейчас подходящее время для этого исследования.

Говорят, что последняя версия Tomcat (6.0.28 или 6.0.29) решает задачу повторного развертывания сервлетов. много лучше.

Я столкнулся с точно такой же проблемой, но, к сожалению, ни одно из предложенных решений мне не помогло.Проблема не возникла во время развертывания, и я не делал никаких горячих развертываний.

В моем случае проблема возникала каждый раз в одном и том же месте во время выполнения моего веб-приложения при подключении (через спящий режим) к базе данных.

Эта ссылка (также упоминавшийся ранее) предоставил достаточно внутренних компонентов для решения проблемы.Перемещение драйвера jdbc-(mysql) из WEB-INF в папку jre/lib/ext/, похоже, решило проблему.Это не идеальное решение, поскольку для обновления до более новой версии JRE потребуется переустановить драйвер.Еще одним кандидатом, который может вызвать аналогичные проблемы, является log4j, поэтому вы также можете переместить его.

Первым шагом в таком случае является проверка, разрешено ли сборщику мусора выгружать классы из PermGen.Стандартная JVM в этом отношении довольно консервативна — классы рождаются, чтобы жить вечно.Таким образом, после загрузки классы остаются в памяти, даже если никакой код их больше не использует.Это может стать проблемой, если приложение динамически создает множество классов и сгенерированные классы не нужны в течение длительного периода времени.В таком случае может оказаться полезным разрешить JVM выгружать определения классов.Этого можно добиться, добавив в сценарии запуска всего один параметр конфигурации:

-XX:+CMSClassUnloadingEnabled

По умолчанию для этого параметра установлено значение false, поэтому, чтобы включить его, вам необходимо явно установить следующий параметр в параметрах Java.Если вы включите CMSClassUnloadingEnabled, GC также очистит PermGen и удалит классы, которые больше не используются.Имейте в виду, что этот параметр будет работать только в том случае, если UseConcMarkSweepGC также включен с помощью параметра ниже.Поэтому при запуске ParallelGC или, не дай Бог, Serial GC убедитесь, что для вашего GC настроен CMS, указав:

-XX:+UseConcMarkSweepGC

Выделение Tomcat большего объема памяти НЕ является правильным решением.

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

Если ваш сервер Tomcat/Webapp сообщает вам, что не удалось отменить регистрацию драйверов (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>  

«Они» ошибаются, потому что я использую 6.0.29 и имею ту же проблему даже после установки всех параметров.Как сказал выше Тим Хауленд, эти варианты лишь отсрочивают неизбежное.Они позволяют мне выполнять повторное развертывание 3 раза, прежде чем возникнет ошибка, вместо того, чтобы выполнять повторное развертывание каждый раз.

Если вы получаете это в IDE eclipse, даже после установки параметров--launcher.XXMaxPermSize, -XX:MaxPermSize, и т. д., но если вы получаете ту же ошибку, скорее всего, затмение использует ошибочную версию JRE, которая была бы установлена ​​некоторыми сторонними приложениями и настроена по умолчанию.Эти ошибочные версии не принимают параметры PermSize, поэтому независимо от того, что вы устанавливаете, вы все равно продолжаете получать эти ошибки памяти.Итак, в ваш eclipse.ini добавьте следующие параметры:

-vm <path to the right JRE directory>/<name of javaw executable>

Также убедитесь, что вы установили JRE по умолчанию в настройках затмения на правильную версию Java.

Единственный способ, который мне помог, — это JRockit JVM.У меня MyEclipse 8.6.

В куче JVM хранятся все объекты, созданные работающей программой Java.Java использует new оператор для создания объектов, а память для новых объектов выделяется в куче во время выполнения.Сбор мусора — это механизм автоматического освобождения памяти, содержащейся в объектах, на которые больше не ссылается программа.

У меня была похожая проблема.У меня это JDK 7 + Maven 3.0.2 + Struts 2.0 + проект, основанный на внедрении зависимостей Google GUICE.

Всякий раз, когда я пытался бежать mvn clean package команда, она показывала следующую ошибку и «СТРОИТЕЛЬНЫЙ ПРОВАЛ» произошло

org.apache.maven.surefire.util.SurefireReflectionException:java.lang.reflect.IndictionTargetException;вложенным исключением является java.lang.reflect.InvocatingTargetException:null java.lang.reflect.invocationTargetException, вызванный:java.lang.OutOfMemoryError:ПермГен пространство

Я попробовал все вышеперечисленные полезные советы и рекомендации, но, к сожалению, ни один из них мне не помог.То, что сработало для меня, описано шаг за шагом ниже :=>

  1. Перейдите в свой pom.xml
  2. Искать <artifactId>maven-surefire-plugin</artifactId>
  3. Добавить новый <configuration> элемент, а затем <argLine> подэлемент, в котором проходят -Xmx512m -XX:MaxPermSize=256m как показано ниже =>

<configuration> <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine> </configuration>

Надеюсь, это поможет, удачного программирования :)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top