Как бороться с ошибкой "java.lang.OutOfMemoryError: Java heap space"?

Я пишу клиентское приложение Качать (дизайнер графических шрифтов) на Java 5. Недавно я столкнулся с ошибкой java.lang.OutOfMemoryError: Java heap space, потому что я не консервативен в использовании памяти. Пользователь может открывать неограниченное количество файлов, а программа сохраняет открытые объекты в памяти. После быстрого исследования я обнаружил, что Эргономика виртуальной машины Java 5.0 и другие говорят, что на машине Windows JVM по умолчанию устанавливает максимальный размер кучи как 64MB.

В этой ситуации, как мне справиться с этим ограничением?

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

Я мог бы переписать часть своего кода, чтобы часто сохранять объекты в файловой системе (использование базы данных - то же самое), чтобы освободить память. Это могло бы сработать, но, вероятно, это тоже много работы.

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

Максимальный размер кучи по умолчанию - 64 МБ - до J2SE 5.0. Для получения информации о J2SE 8.0 см. «Эргономика сборщика мусора» на docs.oracle.com/javase/8/docs/technotes/guides/vm/….

Andy Thomas 08.04.2015 18:36

Если вы попали сюда, потому что каждый вопрос OOM дублирован на этот, убедитесь, что вы также проверяли: stackoverflow.com/questions/299659/… Он предоставляет решение для очистки ссылок на память «как раз вовремя» перед OOM. SoftReferences может быть инструментом, который решит вашу актуальную проблему.

Steve Steiner 24.04.2018 23:13

JVM Sun / Oracle всегда была довольно жесткой в ​​отношении определения объема используемой памяти (и наличия некоторых интересных значений по умолчанию, если они оставлены сами по себе). В то время это была одна из приятных особенностей Microsoft JVM - это была быстрый, и она могла использовать любую память, имеющуюся на машине.

Thorbjørn Ravn Andersen 21.02.2021 19:12
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
452
3
1 482 785
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Ответ принят как подходящий

В конечном итоге у вас всегда есть конечный максимум кучи, независимо от того, на какой платформе вы работаете. В 32-разрядной версии Windows это примерно 2GB (не конкретно куча, а общий объем памяти на процесс). Просто так случается, что Java предпочитает уменьшить значение по умолчанию (предположительно, чтобы программист не мог создавать программы с неконтролируемым распределением памяти, не столкнувшись с этой проблемой и не проверяя, что именно они делают).

Итак, учитывая, что есть несколько подходов, которые вы можете использовать, чтобы определить, какой объем памяти вам нужен, или уменьшить объем памяти, который вы используете. Одна из распространенных ошибок языков со сборкой мусора, таких как Java или C#, состоит в том, чтобы хранить ссылки на объекты, которые вы используете больше никогда, или выделять много объектов, когда вы могли бы вместо них повторное использование. Пока объекты имеют ссылку на них, они будут продолжать использовать пространство кучи, поскольку сборщик мусора не удалит их.

В этом случае вы можете использовать профилировщик памяти Java, чтобы определить, какие методы в вашей программе выделяют большое количество объектов, а затем определить, есть ли способ убедиться, что на них больше нет ссылок, или не выделять их в первую очередь. Один из вариантов, который я использовал в прошлом, - это "JMP" http://www.khelekore.org/jmp/.

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

В общем, если вы не можете гарантировать, что ваша программа будет работать в некотором ограниченном объеме памяти (возможно, в зависимости от размера ввода), вы всегда будете сталкиваться с этой проблемой. Только после того, как вы исчерпали все это, вам нужно будет изучить кеширование объектов на диск и т. д. На этом этапе у вас должна быть очень веская причина сказать «Мне нужен Xgb памяти» для чего-то, и вы не можете обойти это, улучшив ваши алгоритмы или шаблоны распределения памяти. Обычно это происходит только с алгоритмами, работающими с большими наборами данных (например, с базой данных или какой-либо программой научного анализа), и тогда становятся полезными такие методы, как кэширование и ввод-вывод с отображением памяти.

OpenJDK и OracleJDK объединяют профилировщик - jvisualvm. Если вам нужны дополнительные удобства, я бы предложил коммерческий Yourkit.

Petr Gladkikh 17.04.2013 08:40

Запустите Java с параметром командной строки -Xmx, который устанавливает размер кучи максимум.

Подробнее см. Здесь.

Как установить этот параметр навсегда? Потому что я использую команду «gradlew assembly».

Dr.jacky 19.01.2017 10:32

Выполнить-> Выполнить конфигурации-> Щелкните аргументы-> внутри типа аргументов виртуальной машины -Xms1g -Xmx2g

Arayan Singh 24.05.2018 21:38

Это настоящий ответ.

nccc 14.08.2019 19:58

Да, с помощью -Xmx вы можете настроить больше памяти для вашей JVM. Чтобы убедиться, что вы не теряете и не тратите память. Возьмите дамп кучи и используйте анализатор памяти Eclipse для анализа потребления памяти.

JVMJ9VM007E Неизвестный параметр командной строки: -Xmx Не удалось создать виртуальную машину Java. Голосовать против

Philip Rego 16.01.2019 01:28

Если вам нужно контролировать использование памяти во время выполнения, пакет java.lang.management предлагает MBeans, который можно использовать для мониторинга пулов памяти в вашей виртуальной машине (например, пространство eden, временное поколение и т. д.), А также поведение при сборке мусора.

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

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

Большое предостережение - в моем офисе мы обнаружили, что (на некоторых машинах с Windows) мы не можем выделить более 512 м для кучи Java. Оказалось, что это связано с тем, что на некоторых из этих машин был установлен антивирус Касперского. После удаления этого продукта AV мы обнаружили, что можем выделить не менее 1,6 ГБ, то есть -Xmx1600m (m является обязательным, иначе это приведет к другой ошибке «Слишком маленькая начальная куча»).

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

Обратите внимание, что если вам это нужно в ситуации развертывания, рассмотрите возможность использования Java WebStart (с версией «на диске», а не сетевой - возможно в Java 6u10 и более поздних версиях), поскольку он позволяет вам указывать различные аргументы для JVM крестиком. платформенный способ.

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

Java WebStart постепенно прекращается. Я пока не знаю подходящей замены.

Thorbjørn Ravn Andersen 31.12.2018 15:33

Я читал где-то еще, что вы можете попробовать - поймать java.lang.OutOfMemoryError и в блоке catch вы можете освободить все ресурсы, которые, как вы знаете, могут использовать много памяти, закрыть соединения и т. д., Затем выполнить System.gc(), а затем повторить попытку что бы ты ни делал.

Другой способ - это, хотя я не знаю, сработает ли это, но в настоящее время я тестирую, будет ли это работать в моем приложении.

Идея состоит в том, чтобы выполнить сборку мусора путем вызова System.gc (), который, как известно, увеличивает свободную память. Вы можете продолжать проверять это после выполнения кода, поглощающего память.

//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);

Runtime runtime = Runtime.getRuntime();

if (runtime.freeMemory()<minRunningMemory)
 System.gc();

В общем, я думаю, что JVM предпочтет сборку мусора (GC), а не выбросить OutOfMemoryError. Явный вызов System.gc () после OutOfMemoryError может помочь на некоторых виртуальных машинах / конфигурациях, но я не ожидал бы, что он будет работать очень хорошо в общем случае. Однако удаление ненужных ссылок на объекты определенно поможет почти во всех случаях.

Mike Clark 20.11.2010 13:50

@mwangi Вызов System.gc () непосредственно из кода, как правило, плохая идея. GC должен быть выполнен просто предложение для JVM, но есть абсолютно нет гарантии, что он будет выполнен.

user1014581 26.10.2011 16:51

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

Один из вариантов - закрыть и открыть прозрачный файл, когда они переключают вкладки (вы сохраняете только указатель на файл, а когда пользователь переключает вкладку, вы закрываете и очищаете все объекты ... это замедлит изменение файла ... но ...) и, возможно, хранить в памяти только 3 или 4 файла.

Еще вам следует сделать следующее: когда пользователь открывает файл, загружает его и перехватывает любую OutOfMemoryError, затем (поскольку открыть файл невозможно) закрыть этот файл, очистить его объекты и предупредить пользователя, что он должен закрыть неиспользуемые файлы.

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

Вот пара подсказок, которые я видел в связи с утечками памяти:

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

-> Возможно, использование коллекций со слабыми ссылками (weakhashmap ...) может помочь с проблемами памяти, но вы должен будьте осторожны с этим, поскольку вы можете обнаружить, что объект, который вы ищете, был собран.

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

Вы можете указать проект на, сколько места в куче требуется вашему проекту

Следующее для Затмение Гелиос / Юнона / Кеплер:

Щелкните правой кнопкой мыши на

 Run As - Run Configuration - Arguments - Vm Arguments, 

затем добавьте это

-Xmx2048m

привет bighostkim и cuongHuyTo, где находится «Аргументы» .. Я могу увидеть конфигурацию запуска до. Пожалуйста, позвони мне. Мне нужно скачать и сохранить около 2000 контактов из Gmail. Сбой из-за исключения нехватки памяти

AndroidRaji 24.11.2012 09:49

@AndroiRaji: вы щелкаете правой кнопкой мыши по классу Java, который имеет исполняемый main (то есть «public static void main (String [] args)»), затем выбираете Run As - Run Configuration. Затем «Аргументы» - это вкладка сразу после основной (вы видите вкладки Основные, Аргументы, JRE, Путь к классам, Источник, Среда, Общие).

CuongHuyTo 04.03.2014 14:06

Как бы было на intellih?

Jimmy 17.07.2020 09:47

Я столкнулся с той же проблемой из-за размера кучи java.

У меня есть два решения, если вы используете java 5 (1.5).

  1. просто установите jdk1.6, перейдите в настройки eclipse и установите путь jre для jav1 1.6, как вы установили.

  2. Проверьте свой аргумент ВМ, и пусть все будет так, как есть. просто добавьте одну строку ниже всех аргументов, присутствующих в аргументах VM, как -Xms512m -Xmx512m -XX: MaxPermSize = ... м (192 м).

Думаю сработает ...

Аргументы VM сработали для меня в eclipse. Если вы используете eclipse версии 3.4, сделайте следующее

перейдите к Run --> Run Configurations -->, затем выберите проект в разделе maven build -> затем выберите вкладку «JRE» -> затем введите -Xmx1024m.

В качестве альтернативы вы можете сделать Run --> Run Configurations --> select the "JRE" tab -->, а затем ввести -Xmx1024m

Это должно увеличить кучу памяти для всех сборок / проектов. Указанный выше объем памяти составляет 1 ГБ. Вы можете оптимизировать так, как хотите.

Простой способ решить OutOfMemoryError в java - увеличить максимальный размер кучи с помощью параметров JVM -Xmx512M, это немедленно устранит вашу OutOfMemoryError. Это мое предпочтительное решение, когда я получаю OutOfMemoryError в Eclipse, Maven или ANT при создании проекта, потому что в зависимости от размера проекта у вас может легко закончиться память.

Вот пример увеличения максимального размера кучи JVM. Также лучше сохранить соотношение -Xmx к -Xms либо 1: 1, либо 1: 1.5, если вы устанавливаете размер кучи в своем java-приложении.

export JVM_ARGS = "-Xms1024m -Xmx1024m"

Ссылка Ссылка

Есть идеи, почему нам нужно держать их в соотношении 1: 1 или 1: 1,5?

ernesto 25.10.2012 14:56

Выполните следующие шаги:

  1. Откройте catalina.sh из tomcat / bin.

  2. Измените JAVA_OPTS на

    JAVA_OPTS = "-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m 
    -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m 
    -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
    
  3. Перезагрузите вашего кота

Увеличение размера кучи - это не «исправление», это «штукатурка», на 100% временная. Он снова рухнет где-нибудь еще. Чтобы избежать этих проблем, напишите высокопроизводительный код.

  1. По возможности используйте локальные переменные.
  2. Убедитесь, что вы выбрали правильный объект (Пример: выбор между String, StringBuffer и StringBuilder)
  3. Используйте хорошую систему кода для своей программы (пример: использование статических переменных VS нестатических переменных)
  4. Другие вещи, которые могут работать с вашим кодом.
  5. Попробуйте двигаться с многопоточным НАПРАВЛЕНИЕМ

Это правда. Я пытаюсь исправить одну проблему, когда я получаю OOM в потоке AWT, но если я использую другой новый поток, у меня не возникает проблема с OOM. Все, что я могу найти в Интернете, - это увеличить размер кучи для потока AWT.

Ashish 11.02.2019 08:43

@Ash: Да, устраните основную проблему вместо того, чтобы искать пластыри.

PeakGen 12.02.2019 10:59

Сборка мусора и подход к управлению памятью в Java должен был решить все эти сложности с malloc-dealloc, присущие его предшественникам :( Конечно, я полностью согласен с этим ответом, просто жаль, что значения по умолчанию не позволяют легко писать код с бережливыми данными -структуры, которые убираются как можно скорее.

Davos 11.10.2019 14:51

Хочу добавить рекомендации из статьи oracle Поиск неисправностей.

Исключение в потоке имя_потока: java.lang.OutOfMemoryError: пространство кучи Java

The detail message Java heap space indicates object could not be allocated in the Java heap. This error does not necessarily imply a memory leak

Возможные причины:

  1. Проблема простой конфигурации, где указанный размер кучи недостаточен для приложения.

  2. Приложение непреднамеренно содержит ссылки на объекты, и это предотвращает сборку мусора для объектов.

  3. Чрезмерное использование финализаторов.

One other potential source of this error arises with applications that make excessive use of finalizers. If a class has a finalize method, then objects of that type do not have their space reclaimed at garbage collection time

После вывоз мусора объекты ставятся в очередь для завершение, что происходит позже. финализаторы выполняются потоком демона, который обслуживает очередь финализации. Если поток финализатор не может идти в ногу с очередью финализации, тогда куча Java может заполниться, и возникнет исключение OutOfMemoryError этого типа.

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

По умолчанию для разработки JVM использует небольшой размер и небольшую конфигурацию для других функций, связанных с производительностью. Но для производства вы можете настроить, например, (Кроме того, может существовать специфическая конфигурация сервера приложений) -> (Если памяти все еще недостаточно для удовлетворения запроса, а куча уже достигла максимального размера, произойдет OutOfMemoryError)

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size
-Xss<size>        set java thread stack size

-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)

Например: на платформе linux предпочтительные настройки для производственного режима.

После скачивания и настройки сервера таким образом http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/

1. создать файл setenv.sh в папке / opt / tomcat / bin /

   touch /opt/tomcat/bin/setenv.sh

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

nano  /opt/tomcat/bin/setenv.sh 

export CATALINA_OPTS = "$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS = "$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS = "$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS = "$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS = "$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS = "$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS = "$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS = "$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"

3.service tomcat restart

Note that the JVM uses more memory than just the heap. For example Java methods, thread stacks and native handles are allocated in memory separate from the heap, as well as JVM internal data structures.

Если эта проблема возникает в Wildfly 8 и JDK1.8, тогда нам нужно указать настройки MaxMetaSpace вместо настроек PermGen.

Например, нам нужно добавить ниже конфигурацию в файл setenv.sh wildfly. JAVA_OPTS = "$JAVA_OPTS -XX:MaxMetaspaceSize=256M"

Для получения дополнительной информации, пожалуйста, проверьте Проблема с кучей Wildfly

Что касается netbeans, вы можете установить максимальный размер кучи, чтобы решить проблему.

Перейдите в «Выполнить», затем -> «Установить конфигурацию проекта» -> «Настроить» -> «Выполнить» его всплывающее окно -> «Вариант виртуальной машины» -> заполните «-Xms2048m -Xmx2048m» .

Если ничего не помогает, попробуйте увеличить не только максимальный размер кучи, но и размер подкачки. Для Linux на данный момент соответствующие инструкции можно найти в https://linuxize.com/post/create-a-linux-swap-file/.

Это может помочь, если вы, например, компилирование чего-то большого на встроенной платформе.

если вы получили эту ошибку при запуске eclipse birt 1- вы зайдете в файл конфигурации eclipse 2- вы должны открыть eclipse.init 3- модифицировал оперативную память, вы можете увеличить это, я привожу пример.

моя старая информация была: -Xmx128м -XX: MaxPermSize = 128 м

новая модификация, которую я опробовал:

-Xmx512m -XX: MaxPermSize = 512 м

эта модификация позволит мне разрешить пространство кучи java при запуске отчета в браузере.

Спасибо

В студии Android добавьте / измените эту строку в конце gradle.properties (Global Properties):

...
org.gradle.jvmargs=-XX\:MaxHeapSize\=1024m -Xmx1024m 

если это не сработает, вы можете повторить попытку с размером кучи больше 1024.

Другие вопросы по теме