Работа с " java.ленг.OutOfMemoryError: ошибка PermGen space

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

java.ленг.OutOfMemoryError: PermGen space

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

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

30 ответов


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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

tomcat6w //ES//servicename

здесь - это имя сервера, отображаемое в сервисах.msc

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


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

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


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

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


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

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

теперь есть два способа решить эту проблему:
1. Найдите причину утечки памяти или если есть какая-либо утечка памяти.
2. Увеличьте размер пространства PermGen с помощью JVM param -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. В большинстве JVM,по умолчанию PermSize вокруг 64 МБ у которого заканчивается память, если в проекте слишком много классов или огромное количество строк.

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

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

enter image description here

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

enter image description here


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

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

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

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

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

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

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

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

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


на 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_8_Download или выше.


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

    -XX:MaxPermSize=128m
    
  3. установите начальный пул памяти в 1024 (необязательно).
  4. установите максимальный пул памяти в 1024 (необязательно).
  5. Нажмите Ok.
  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 в своем webapp, проверьте этот абзац в 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 имеет горячее развертывание, но потребляет память. Попробуйте перезапустить контейнер время от времени. Также вам нужно будет знать объем памяти, необходимый для работы в производственном режиме, это кажется хорошим временем для этого исследования.


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


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

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

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


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

-XX:+CMSClassUnloadingEnabled

по умолчанию установлено значение false, поэтому для включения этого необходимо явно установить следующий параметр в Java options. Если вы включите 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 и поэтому независимо от того, что вы установили, вы по-прежнему получать эти ошибки памяти. Итак, в вашем затмении.ini добавить следующее параметры:

-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 на основе инъекций зависимостей.

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

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

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

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

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

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