Работа с " java.ленг.Исключение OutOfMemoryError: PermGen пространства" ошибка


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

java.ленг.OutOfMemoryError: PermGen space

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

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

30 1190

30 ответов:

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

tomcat6w //ES//servicename

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

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

ты лучше попробуй -XX:MaxPermSize=128M, а не -XX:MaxPermGen=128M.

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

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

посмотреть classloader утечки: страшный " java.ленг.OutOfMemoryError: PermGen space " exception и followup post.

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

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

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

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

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

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

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

для eclipse, он также описан в ответ.

Шаг 1: дважды щелкните на сервере tomcat по адресу сервера Tab

enter image description here

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

enter image description here

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

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

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

и после нескольких повторных развертываний мы сталкиваемся с 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();

кроме того, вы можете переключиться на JRockit, который обрабатывает permgen по-разному, а затем JVM sun. Он, как правило, имеет лучшую производительность, а также.

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

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

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

 -XX:MaxPermSize=128m

по умолчанию 64m.

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

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

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

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

в eclipse перейти к сервера вкладка дважды щелкните на зарегистрированном сервере в моем случае tomcat 7.0, он открывает общую регистрационную информацию о моем файловом сервере. На секции "Общая Информация" нажмите на ссылку "конфигурация запуска", это открывает выполнение параметров сервера на вкладке аргументы в аргументах VM, добавленных в конце этих двух записей

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

и готово.

самый простой ответ в эти дни-использовать Java 8.

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

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

The 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_Download или выше.

  1. откройте tomcat7w из каталога bin Tomcat или введите монитор Tomcat в меню Пуск (откроется окно с вкладками, содержащее различную служебную информацию).
  2. в текстовой области параметров Java добавьте эту строку:

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

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

выполнить команду gedit .bashrc на терминал.

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

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

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

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

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

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

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

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

Set -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>

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

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

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

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

какова сумма предварительно обработанных транзакций?

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

etc.

etc.

etc

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

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

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

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

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

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

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

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

-XX:+CMSClassUnloadingEnabled

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

-XX:+UseConcMarkSweepGC

назначение Tomcat больше памяти не является правильным решением.

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

Если ваш сервер Tomcat / Webapp сообщает вам, что не удалось отменить регистрацию драйверов (JDBC), то отмените их регистрацию. Это остановит утечку памяти.

Вы можете создать ServletContextListener и настроить его в интернете.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();
        }        
    }
}

и здесь вы настраиваете его в своем интернете.XML-код:

<listener>
    <listener-class>
        com.calculistik.mediweb.context.AppContextListener 
    </listener-class>
</listener>  

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

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

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

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

единственный способ, который работал для меня, был с JRockit JVM. У меня есть MyEclipse 8.6.

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

у меня была аналогичная проблема. Мой-JDK 7 + Maven 3.0.2 + Struts 2.0 + Google GUICE dependency injection based project.

всякий раз, когда я пробовал использовать mvn clean package команда, она показывала следующую ошибку и "ОШИБКА СБОРКИ" ошибка

org.апаш.знаток.верный.утиль.SurefireReflectionException: java.ленг.отражать.InvocationTargetException; вложенным исключением является java.ленг.отражать.InvocationTargetException: null Ява.ленг.отражать.InvocationTargetException Вызвано: java.ленг.OutOfMemoryError: PermGen space

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

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

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

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