java lang outofmemoryerror metaspace как исправить
Какие бывают типы OutOfMemoryError или из каких частей состоит память java процесса
Область памяти, занимаемая java процессом, состоит из нескольких частей. Тип OutOfMemoryError зависит от того, в какой из них не хватило места.
1. java.lang.OutOfMemoryError: Java heap space
2. java.lang.OutOfMemoryError: PermGen space
3. java.lang.OutOfMemoryError: GC overhead limit exceeded
4. java.lang.OutOfMemoryError: unable to create new native thread
Впервые я столкнулся с данной ошибкой несколько лет назад, когда занимался нагрузочным тестированием и пытался выяснить максимальное количество пользователей, которые могут работать с нашим веб-приложением. Я использовал специальную тулзу, которая позволяла логинить пользователей и эмулировать их стандартные действия. На определенном количестве клиентов, я начал получать OutOfMemoryError. Не особо вчитываясь в текст сообщения и думая, что мне не хватает памяти на создание сессии пользователя и других необходимых объектов, я увеличил размер кучи приложения (-Xmx). Каково же было мое удивление, когда после этого количество пользователей одновременно работающих с системой только уменьшилось. Давайте подробно разберемся как же такое получилось.
На самом деле это очень просто воспроизвести на windows на 32-битной машине, так как там процессу выделяется не больше 2Гб.
Более подробно, что же лежит в стеке потока, и куда уходит эта память, можно прочитать тут.
Конечно, вам может показаться данная проблема слегка надуманной, так как большинство серверов нынче крутиться на 64-битной архитектуре, но все же считаю данный пример весьма полезным, так как он помогает разобраться из каких частей состоит память java-процесса.
Работа с » java.ленг.OutOfMemoryError: ошибка PermGen space
недавно я столкнулся с этой ошибкой в моем веб-приложения:
java.ленг.OutOfMemoryError: PermGen space
Это типичное приложение Hibernate/JPA + IceFaces / JSF, работающее на Tomcat 6 и JDK 1.6. По-видимому, это может произойти после повторного развертывания приложения несколько раз.
что вызывает это и что можно сделать, чтобы избежать этого? Как решить проблему?
30 ответов
решением было добавить эти флаги в командную строку JVM при запуске Tomcat:
Если вы получаете ошибку указанная служба не существует как установленная служба вы должны беги:
источник: комментарий orx на гибкие ответы Эрика.
Я не могу сказать точное использование этого пула памяти, но это связано с количеством классов, загруженных в JVM. (Таким образом, включение разгрузки класса для tomcat может решить проблему.) Если ваши приложения генерируют и компилируют классы во время выполнения, скорее всего, потребуется пул памяти больше, чем по умолчанию.
ошибки сервера приложений PermGen, которые происходят после нескольких развертываний, скорее всего, вызваны ссылками, содержащимися контейнером в загрузчиках классов ваших старых приложений. Например, использование пользовательского класса уровня журнала приведет к тому, что загрузчик классов сервера приложений будет содержать ссылки. Вы можете обнаружить эти утечки между классами, используя современные инструменты анализа JVM (JDK6+), такие как jmap и jhat, чтобы посмотреть, какие классы продолжают храниться в вашем приложении, и перепроектировать или исключить их использование. Обычный подозреваемыми являются базы данных,регистраторы и другие библиотеки базового уровня.
распространенные ошибки, которые люди делают, думают, что пространство кучи и пространство permgen одинаковы, что совсем не верно. У вас может быть много места, оставшегося в куче, но все еще может закончиться память в permgen.
распространенными причинами OutofMemory в PermGen является ClassLoader. Всякий раз, когда класс загружается в JVM, все его метаданные вместе с Classloader хранятся в области PermGen, и они будут собраны, когда загрузчик классов, который их загрузил, будет готов к мусору коллекция. В случае, если Classloader имеет утечку памяти, чем все классы, загруженные им, останутся в памяти и вызовут permGen outofmemory, как только вы повторите его пару раз. Классический пример Java.ленг.OutOfMemoryError: пространство PermGen в Tomcat.
вы также можно проверить 2 Решение Java.ленг.Исключение OutOfMemoryError в Java для более подробной информации.
для eclipse он также описан в ответ.
Шаг 1: дважды щелкните по серверу tomcat на сервера Tab
я столкнулся с этой проблемой при развертывании и undeploying сложного веб-приложения тоже, и думал, что я добавлю объяснение и мое решение.
когда я развертываю приложение на Apache Tomcat, для этого приложения создается новый загрузчик классов. Затем ClassLoader используется для загрузки всех классов приложения, а при undeploy все должно уйти красиво. Однако на самом деле все не так просто.
и после нескольких повторных запусков мы сталкиваемся с OutOfMemoryError.
сейчас это стало довольно серьезной проблемой. Я мог бы убедиться, что Tomcat перезапущен после каждое повторное развертывание, но это уничтожает весь сервер, а не только перераспределяемое приложение, что часто невозможно.
поэтому вместо этого я собрал решение в коде, которое работает на Apache Tomcat 6.0. Я не проверял на других серверах приложений, и должен подчеркнуть, что это, скорее всего, не будет работать без изменений на любом другом сервере приложений.
альтернативно, вы можете переключиться на JRockit, который обрабатывает permgen по-разному, чем JVM sun. Оно вообще имеет более лучшее представление также.
OutOfMemoryError: поймай, если сможешь
Всем привет! Сегдня хотел бы поделиться опытом обратоки ошибки ООМ. Эту статью меня побудила написать проблема, с которой я столкнулся. И которая, как позже выяснилось, долгое время оставалсь незамеченой. Меня заинтересовал этот вопрос, так что я решил изучить его немного глубже.
Предистория
У нас есть сервис, который по расписани закидывает задачу по обработке данных в ExecutorService. Это достаточно тяжелая задача. И в один прекрасный момент информации просто стало больше и она не влезла в наш -Xmx.
ООМ своими руками
Для тестирования мне необходимо забить всю память объектами, которые GC будет считать живыми. Для этого я использовал следующий код:
Тут тоже присутствует некоторая проблема, но об этом позже.
Обычный код
Этот код вроде бы выглядит неплохо, ничего особенного тут нет. Наверное, многие писали что-то подобное не один раз. Но проблема в том, что прм ООМ, не будет выведено вообще ничего. Ни в лог ни в поток вывода.
Лови Throwable — говорили они
Да точно, ведь OutOfMemoryError — это Error, а не Exception. Поэтому тут он успешно прлетает мимо catch блока и перехватывается уже в коде ThreadPoolExecutor. Где проглатывается, а сам поток начинает ждать новой задачи. Всем известно, что в самой корневой точке кода лучше ловить Throwable.
К сожалению, если вместо Exception в данной ситуации поймать Throwable, ничего не изменится. При вызове logger.error(), мы просто получим новый ООМ, который так же канет в недрах ThreadPoolExecutor.
Стоит заметить, что если бы вместо ExecutorService создавался бы новый Thread, то все ошибки в конечном счете были бы обработаны UncaughtExceptionHandler в случае смерти потока, и в stderr была бы информация. ThreadPoolExecutor же пытается переиспользовать потоки, что в принципе ожидаемо.
Потерянный OutOfMemoryError
Закидывая задачу в ExecutorService, мы забыли очень важную вещь — воспользоваться Future, который возвращает метод submit().
Теперь стало немного лучше. Если logger.error() выкинет новый ООМ, то main поток свалится и, возможно, выведет ошибку. Это помогает вытащить результат из ExecutorService наружу. Все видели что-то подобное:
Это сообщение выводит обработчик ошибок по умолчанию, который вызывается в случае непредвиденной смерти потока.
UncaughtExceptionHandler — не панацея
Не стоит радоваться раньше вреени, т.к. лучше стало совсем немного. Если не переопределить обработчик, то вызывается ThreadGroup.uncaughtException(), в котором есть следующий код:
Первая же строка создает новый объект при помощи конкатенации и, если там не вылетит новый ООМ, то есть большая вероятность получить его в printStackTrace(). Тут все зависит от обстоятельств. Но суть в том, что даже получив ООМ в главном потоке, есть шанс ничего о нем не узнать.
Финализируй это
Итак, теперь наша проблема в том, что нет памяти для логирования. Из-за чего получаем вторую ошибку. Так может быть попробуем освободить пространство? Проблема заключчается в том, что MemoryGrabber.array — статическая переменная. И объекты доступные через нее GC считает живыми. Попробую ее почистить.
Теперь во время логирования будет вызван сборщик мусора, который уже сможет удалить ненужную структуру данных.
Ода функциональному программированию
Вначале я сказал, что в MemoryGrabber есть проблема. Она заключается в статической переменной array. Дело в том, что эта переменная продолжает жить после того момента, как все свалилось с ошибкой. Очевыдным костылем является ее обнуление в блоке finaly. Было бы намного лучше, если она хранилась на стеке вызова.
Теперь нашь лист List превратится в мусор как только завершится метод grabAllMemory. Не важно, с ошибкой или без. Почти Scala.
Как надо делать
Надеюсь, мне удалось донести мысль о том, что попытки поймать и обработать OutOfMemoryError в коде — сомнительная затея по ряду причин. Для этих целей лучше полагаться на следующие параметры JVM:
Последние два параметра появились только в JDK 8u92, остальные еще в 1.4. Оптимальным поведением является завершение процесса в случае OutOfMemoryError. Такая логика — самая понятная для всех разработчиков и тех, кто будет поддерживать приложение. Попытки обработать подобные ошибки могут привести к последствиям, неочевидным даже для самого автора.
Выводы
В статье я постарался разобраться в некоторых ошибках, из-за которых могут возникнуть проблемы при появлении ООМ. Чтобы их избежать, нужно иметь в виду:
Solving java.lang.OutOfMemoryError: Metaspace error
The java.lang.OutOfMemoryError: Metaspace indicates that the amount of native memory allocated for Java class metadata is exausted. Let’s how this issue can be solved in standalone applications and cloud applications.
In Java 8 and later, the maximum amount of memory allocated for Java classes (MaxMetaspaceSize) is by default unlimited, so in most cases there is no need to change this setting. On the other hand, if you want to limit the amount of memory allocated for Java classes, you can set it as follows:
And for it to grow it first would have to fill up, forcing a garbage collection in an attempt to free objects and only when it cannot meet its MinMetaspaceFreeRatio (default 40%) goal it would expand the current metaspace. That can however not be greater than 230% of the occupancy after the GC cycle.
How Java Hotspot manages MetaSpace Data
The Java Hotspot manages the space used for metadata as follows: space is requested from the OS and then divided into chunks. A class loader allocates space for metadata from its chunks.
Class metadata is deallocated when the corresponding Java class is unloaded and its chunks are recycled for reuse or returned to the OS. Java classes are unloaded as a result of garbage collection, and garbage collections may be triggered in order to unload classes and deallocate class metadata. When the space committed for class metadata reaches a certain threshold (a high-water mark), a garbage collection is triggered.
After the garbage collection, the high-water mark may be raised or lowered depending on the amount of space freed from class metadata.
Checking MetaSpace capacity with jstat
And here is a description of the Labels:
This will print the Metaspace utilization as a percentage of the space’s current capacity.
Querying the Meta Space from an Heap Dump
Further inspection can be performed through an Heap Dump:
Then, if you have a look at the OQL console, you can execute OQL queries to perform ad hoc analysis on your classes. For example, by executing the following query, you can have a list of class loaded from each Classloader:
This can be a precious hint to determine if a Classloader is loading an increasing number of classes.
Monitoring MetaSpace Size with Java Native Memory tracking
A good way to monitor the exact amount of Metadata is by using the NativeMemoryTracking, which can be added through the following settings:
When Native Memory Tracking is enabled, you can request a report on the JVM memory usage using the following command:
If you check at the jcmd output, you will find at the bottom, the amount of native memory committed/used in the Internal (committed) section
In the line beginning with Metaspace, the used value is the amount of space used for loaded classes. The committed value is the amount of space available for chunks. The reserved value is the amount of space reserved (but not necessarily committed) for metadata.
OutOfMemoryError: Metaspace on OpenShift/Kubernetes
When using openjdk Image on OpenShift/Kubernetes, the default maxium value for the Metaspace is XX:MaxMetaspaceSize=100m. You might have noticed that setting this value through the JAVA_OPTIONS environment variable, doesn’t work as the default value is appended to the bottom:
Понимание исключения OutOfMemoryError в Java
В Java все объекты хранятся в куче. Они размещены с использованием нового оператора. Исключение OutOfMemoryError в Java выглядит следующим образом:
Обычно эта ошибка выдается, когда виртуальная машина Java не может выделить объект, потому что ему не хватает памяти, и сборщик мусора не может выделить больше памяти.
OutOfMemoryError обычно означает, что вы что-то делаете неправильно, либо слишком долго держитесь за объекты, либо пытаетесь обрабатывать слишком много данных за раз. Иногда это указывает на проблему, которая находится вне вашего контроля, например на стороннюю библиотеку, которая кэширует строки, или на сервере приложений, который не очищается после развертывания. И иногда это не имеет ничего общего с объектами в куче.
Исключение java.lang.OutOfMemoryError также может быть вызвано собственным библиотечным кодом, когда не удается удовлетворить собственное распределение (например, если пространство подкачки мало). Давайте разберемся в различных случаях, когда может возникнуть ошибка OutOfMemory.
Симптом или первопричина?
Чтобы найти причину, текст исключения включает подробное сообщение в конце. Давайте рассмотрим все ошибки.
// Java-программа для иллюстрации
// Ошибка кучи
static List list = new ArrayList ();
public static void main(String args[]) throws Exception
Integer[] array = new Integer[ 10000 * 10000 ];
// Java-программа для иллюстрации
// превышен лимит GC
public class Wrapper <
public static void main(String args[]) throws Exception
Map m = new HashMap();
Random r = new Random();
// Java-программа для иллюстрации
// Ошибка Пермгенского пространства
public class Permgen <
static ClassPool classPool = ClassPool.getDefault();
public static void main(String args[]) throws Exception
for ( int i = 0 ; i 1000000000 ; i++) <
Class c = classPool.makeClass(com.saket.demo.Permgen» + i).toClass();
// Java-программа для иллюстрации
// Ошибка метапространства
public class Metaspace <
static javassist.ClassPool cp = javassist.ClassPool.getDefault();
public static void main(String args[]) throws Exception
for ( int i = 0 ; i 100000 ; i++) <
Class c = cp.makeClass( «com.saket.demo.Metaspace» + i).toClass();
// Java-программа для иллюстрации
// запрашиваемый размер массива
// превышает ошибку лимита виртуальной машины
static List list = new ArrayList ();
public static void main(String args[]) throws Exception
Integer[] array = new Integer[ 10000 * 10000 ];
Java.lang.OutOfMemoryError: Запрашиваемый размер массива превышает ограничение виртуальной машины может появиться в результате одной из следующих ситуаций:
Предупреждение: Когда выдается это сообщение об ошибке, виртуальная машина вызывает механизм обработки фатальных ошибок (то есть генерирует файл журнала фатальных ошибок, который содержит полезную информацию о потоке, процессе и системе во время сбоя). В случае исчерпания собственной кучи полезная информация о памяти и карте памяти в журнале может быть полезной
// Java-программа для иллюстрации
// ошибка нового собственного потока
public static void main(String args[]) throws Exception
new Thread( new Runnable()
catch (InterruptedException e)
Точное ограничение собственного потока зависит от платформы, например, тесты Mac OS X показывают, что:
64-битная Mac OS X 10.9, Java 1.7.0_45 — JVM умирает после создания потоков # 2031
Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.