[exception] Работа с ошибкой «java.lang.OutOfMemoryError: PermGen space»


14 Answers

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

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

Question

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

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

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

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




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



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




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

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

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

и готов.




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

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

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

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




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

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

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




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




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

Всякий раз, когда я пытался запустить mvn clean package , он показывал следующую ошибку и произошел «BUILD FAILURE»

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>

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




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




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

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



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

Что делаешь?

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

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

и т.п.

и т.п.

и т.д

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

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

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




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

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

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




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

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

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

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



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

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




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

Первое, что можно сделать, - увеличить размер пространства кучи постоянного поколения. Это невозможно сделать с помощью обычных аргументов JXM с размерами -Xms (установить размер начальной кучи) и -Xmx (установить максимальный размер кучи), поскольку, как уже упоминалось, пространство кучи постоянного поколения полностью отделено от обычного пространства Java Heap, и эти аргументы заданы пространство для этого регулярного пространства кучи Java. Однако существуют аналогичные аргументы, которые могут быть использованы (по крайней мере, с помощью java / Sun / OpenJDK), чтобы увеличить размер кучи постоянного поколения:

 -XX:MaxPermSize=128m

Значение по умолчанию - 64 м.

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

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

Вы можете найти подробности об этой ошибке.

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




Related