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

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

java.lang.OutOfMemoryError: PermGen space

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

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

Ответы [ 32 ]

4 голосов
/ 08 декабря 2011

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

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

3 голосов
/ 25 апреля 2016

Назначение 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>  
3 голосов
/ 05 января 2016

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

-XX:+CMSClassUnloadingEnabled

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

-XX:+UseConcMarkSweepGC
3 голосов
/ 12 марта 2009

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

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

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

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

и т.д.

и т.д.

и т.д.

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

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

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

3 голосов
/ 19 сентября 2010

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

3 голосов
/ 19 марта 2011

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

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

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

2 голосов
/ 04 сентября 2015

У меня была похожая проблема. Мой 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

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

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

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

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

2 голосов
/ 20 сентября 2010

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

2 голосов
/ 18 ноября 2010

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

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

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

2 голосов
/ 29 ноября 2010

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

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

...