Работа с ошибкой "java.lang.OutOfMemoryError: PermGen space"

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

java.lang.OutOfMemoryError: пространство PermGen

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

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

Ответ 1

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

tomcat6w //ES//servicename

где servicename - это имя сервера, как показано в services.msc

Источник: комментарий orx на Eric Agile Answers.

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

Для eclipse он также описан в answer.

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

enter image description here

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

enter image description here

Ответ 8

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

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

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

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

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

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

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

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

//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();

Ответ 10

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

Первое, что можно сделать, - увеличить размер пространства кучи постоянного поколения. Это невозможно сделать с помощью обычных аргументов JXM с размерами -Xms (установить начальный размер кучи) и -Xmx (установить максимальный размер кучи), поскольку, как уже упоминалось, пространство кучи постоянного поколения полностью отделено от обычного пространства Java Heap, и эти аргументы задают пространство для этого обычного кучного пространства 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

Ответ 11

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

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

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

и готов.

Ответ 12

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

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

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

Ответ 13

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

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

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

enter image description here

Metaspace: появилось новое пространство памяти

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

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

Ответ 14

  • Откройте tomcat7w из каталога Tomcat bin или введите "Монитор Tomcat" в меню "Пуск" (окно с вкладками открывается с различной служебной информацией).
  • В текстовой области Параметры Java добавьте эту строку:

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

Ответ 15

Пространственная ошибка 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, проблема никогда не возникает.

Ответ 16

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

Похоже, что если вы используете PropertyConfigurator.configureAndWatch("log4j.properties"), вы вызываете утечку памяти при отключении вашего webapp.

Ответ 17

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

Ответ 18

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

Ответ 19

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

Ответ 20

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

Ответ 21

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

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

Ответ 22

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

Чем вы занимаетесь?

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

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

и др.

и др.

и т.д.

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

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

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

Ответ 23

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

Ответ 24

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

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

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

Ответ 25

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

-XX:+CMSClassUnloadingEnabled

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

-XX:+UseConcMarkSweepGC

Ответ 26

Назначение 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>  

Ответ 27

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

Ответ 28

Если вы получаете это в 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.

Ответ 29

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

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

Ответ 30

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

Всякий раз, когда я пытался запустить команду mvn clean package, она показывала следующую ошибку и "СТРОГО НЕИСПРАВНОСТИ" .

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; Вложенное исключение - java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Вызвано: java.lang.OutOfMemoryError: пространство PermGen

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

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

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

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