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

exception memory-leaks out-of-memory java-6 permgen

1013773 просмотра

30 ответа

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

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

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

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

Автор: Chris Источник Размещён: 11.11.2019 01:24

Ответы (30)


560 плюса

Решение

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

tomcat6w //ES//servicename

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

Источник: комментарий orx к Agile Ответам Эрика .

Автор: Chris Размещён: 17.09.2008 10:17

250 плюса

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

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

Автор: toesterdahl Размещён: 07.05.2009 03:15

152 плюса

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

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

Автор: Размещён: 05.12.2008 11:43

67 плюса

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

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

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

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

Автор: Peter Размещён: 04.01.2012 02:26

41 плюса

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

Автор: user17163 Размещён: 18.09.2008 03:29

37 плюса

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

Автор: bassist Размещён: 11.03.2009 10:19

27 плюса

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

Для затмения это также описано в ответе .

ШАГ 1 : Двойной щелчок по серверу Tomcat на вкладке Servers

введите описание изображения здесь

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

введите описание изображения здесь

Автор: prayagupd Размещён: 03.03.2013 10:05

22 плюса

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

Когда я развертываю приложение в 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();
Автор: Edward Torbett Размещён: 09.06.2011 09:39

19 плюса

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

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

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

введите описание изображения здесь

Metaspace: рождается новое пространство памяти

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

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

Автор: Santosh Jadi Размещён: 22.03.2016 07:15

15 плюса

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

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

Автор: Jeremy Размещён: 17.09.2008 10:23

15 плюса

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

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

 -XX:MaxPermSize=128m

По умолчанию это 64м.

2) Включить Sweeping

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

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

Автор: faisalbhagat Размещён: 03.09.2014 02:46

13 плюса

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

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

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

и готово.

Автор: Hugo Mendoza Размещён: 03.12.2010 11:40

13 плюса

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

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

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

Автор: Edwin Buck Размещён: 04.08.2014 01:01

8 плюса

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

    -XX:MaxPermSize=128m
    
  3. Установите начальный пул памяти на 1024 (необязательно).
  4. Установите Максимальный пул памяти на 1024 (необязательно).
  5. Нажмите Ok.
  6. Перезапустите сервис Tomcat.
Автор: Lucky Размещён: 20.03.2013 10:08

6 плюса

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

Запустите команду gedit .bashrcна терминале.

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

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

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

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

Автор: Darshan Размещён: 15.09.2014 05:51

5 плюса

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

Автор: Nikem Размещён: 12.07.2012 12:48

5 плюса

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

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

Автор: Yannis Sermetziadis Размещён: 06.06.2011 09:20

4 плюса

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

Автор: Pankaj Shinde Размещён: 01.07.2009 04:54

4 плюса

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

Автор: sandeep Размещён: 28.04.2010 04:51

4 плюса

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

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

Автор: kiwilisk Размещён: 08.12.2011 02:51

4 плюса

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

Автор: Tim Howland Размещён: 18.09.2008 02:09

3 плюса

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

Что делаешь?

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

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

и т.п.

и т.п.

и т.д

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

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

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

Автор: OscarRyz Размещён: 11.03.2009 10:24

3 плюса

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

Автор: Tony Ennis Размещён: 19.09.2010 12:31

3 плюса

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

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

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

Автор: Maze Размещён: 19.03.2011 11:38

3 плюса

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

-XX:+CMSClassUnloadingEnabled

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

-XX:+UseConcMarkSweepGC
Автор: sendon1982 Размещён: 05.01.2016 01:04

3 плюса

Назначение 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>  
Автор: Alejandro Pablo Tkachuk Размещён: 25.04.2016 05:13

2 плюса

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

Автор: Ross Peoples Размещён: 20.09.2010 05:40

2 плюса

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

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

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

Автор: Hrishikesh Kumar Размещён: 18.11.2010 12:48

2 плюса

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

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

Автор: Daniel Размещён: 29.11.2010 07:36

2 плюса

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

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

Автор: NIKHIL CHAURASIA Размещён: 04.09.2015 09:33
Вопросы из категории :
32x32