Как бороться с java.lang.OutOfMemoryError: ошибка пространства кучи Java?

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

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

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

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

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


person Eugene Yokota    schedule 01.09.2008    source источник
comment
Максимальный размер кучи по умолчанию - 64 МБ - до J2SE 5.0. Информацию о J2SE 8.0 см. В разделе «Эргономика сборщика мусора» по адресу docs.oracle.com/javase/8/docs/technotes/guides/vm/.   -  person Andy Thomas    schedule 08.04.2015
comment
Если вы приземлились здесь, потому что каждый вопрос OOM дублирован на этот, обязательно проверьте: stackoverflow.com/questions/299659/ Он предоставляет решение для очистки ссылок на память« точно вовремя »перед OOM. SoftReferences может быть инструментом, который решит вашу актуальную проблему.   -  person Steve Steiner    schedule 24.04.2018
comment
JVM Sun / Oracle всегда была довольно жесткой в ​​отношении определения объема используемой памяти (и наличия некоторых интересных значений по умолчанию, если они оставлены сами по себе). В то время это было одним из достоинств Microsoft JVM - она ​​была быстрой и могла использовать любую память, имеющуюся на машине.   -  person Thorbjørn Ravn Andersen    schedule 21.02.2021


Ответы (24)


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

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

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

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

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

person Ben Childs    schedule 01.09.2008
comment
OpenJDK и OracleJDK объединяют профилировщик - jvisualvm. Если вам нужны дополнительные удобства, я предлагаю коммерческий Yourkit. - person Petr Gladkikh; 17.04.2013

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

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

person Dave Webb    schedule 01.09.2008
comment
Как установить этот параметр навсегда? Потому что я использую команду «gradlew assembly». - person Dr.jacky; 19.01.2017
comment
Выполнить- ›Выполнить конфигурации-› Щелкните по аргументам- ›внутри типа аргументов ВМ -Xms1g -Xmx2g - person Arayan Singh; 24.05.2018

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

Ниже приведено для Eclipse Helios / Juno / Kepler:

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

 Run As - Run Configuration - Arguments - Vm Arguments, 

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

-Xmx2048m
person allenhwkim    schedule 25.02.2011
comment
привет, bighostkim и cuongHuyTo, где находятся аргументы. Я могу видеть конфигурацию запуска. Пожалуйста, позвони мне. Мне нужно скачать и сохранить около 2000 контактов из Gmail. Сбой из-за исключения нехватки памяти - person AndroidRaji; 24.11.2012
comment
@AndroiRaji: вы щелкаете правой кнопкой мыши по классу Java, у которого есть исполняемый main (это public static void main (String [] args)), затем выбираете Run As - Run Configuration. Затем аргументы - это вкладка сразу после основной (вы видите вкладки Основные, Аргументы, JRE, Путь к классам, Источник, Среда, Общие). - person CuongHuyTo; 04.03.2014
comment
Как бы это было для intellih? - person Jimmy; 17.07.2020

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

  1. По возможности используйте локальные переменные.
  2. Убедитесь, что вы выбрали правильный объект (Пример: выбор между String, StringBuffer и StringBuilder)
  3. Используйте хорошую систему кода для своей программы (пример: использование статических переменных VS нестатических переменных)
  4. Другие вещи, которые могут работать с вашим кодом.
  5. Попробуйте двигаться с многопоточным ЗАДВИЖЕНИЕМ
person JustCause    schedule 01.02.2014
comment
Это правда. Я пытаюсь исправить одну проблему, когда я получаю OOM в потоке AWT, но если я использую другой новый поток, у меня не возникает проблема с OOM. Все, что я могу найти в Интернете, - это увеличить размер кучи для потока AWT. - person Ashish; 11.02.2019
comment
@Ash: Да, исправьте основную проблему вместо того, чтобы искать пластыри. - person JustCause; 12.02.2019
comment
Сборка мусора и подход к управлению памятью в Java должен был решить все эти сложности с malloc-dealloc, присущие его предшественникам :( Конечно, я полностью согласен с этим ответом, просто жаль, что значения по умолчанию не позволяют легко писать код с бережливыми данными -структуры, которые убираются как можно скорее. - person Davos; 11.10.2019
comment
Я не согласен. Вам нужно изначально установить для него какое-то значение. Если этого недостаточно, это не обязательно означает, что ваше приложение плохое. Может быть, вы были слишком оптимистичны. В этом случае можно установить более высокое значение. - person Zsolt Sky; 10.06.2021

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

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

person David    schedule 14.04.2009

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

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

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

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

person loveall    schedule 09.06.2011

Я хотел бы добавить рекомендации от Oracle по устранению неполадок статья.

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

Подробное сообщение «Пространство кучи Java» указывает, что объект не может быть размещен в куче Java. Эта ошибка не обязательно означает утечку памяти.

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

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

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

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

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

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

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

person Ravindra babu    schedule 22.03.2016

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

person kohlerm    schedule 09.10.2008
comment
JVMJ9VM007E Неизвестный параметр командной строки: -Xmx Не удалось создать виртуальную машину Java. Голосовать против - person Philip Rego; 16.01.2019

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

  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. Перезагрузите вашего кота

person Pradip Bhatt    schedule 07.10.2013

По умолчанию для разработки 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

Обратите внимание, что JVM использует больше памяти, чем просто куча. Например, методы Java, стеки потоков и собственные дескрипторы размещаются в памяти отдельно от кучи, а также во внутренних структурах данных JVM.

person Musa    schedule 26.05.2016

Я читал где-то еще, что вы можете попробовать - поймать 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();
person mwangi    schedule 17.08.2010
comment
В общем, я думаю, что JVM предпочтет сборку мусора (GC), а не выбросить OutOfMemoryError. Явный вызов System.gc () после OutOfMemoryError может помочь на некоторых виртуальных машинах / конфигурациях, но я не ожидал бы, что он будет работать очень хорошо в общем случае. Однако удаление ненужных ссылок на объекты определенно поможет почти во всех случаях. - person Mike Clark; 20.11.2010
comment
@mwangi Вызов System.gc () непосредственно из кода, как правило, плохая идея. Это всего лишь предложение для JVM, что следует выполнить сборку мусора, но нет абсолютно никакой гарантии, что это будет выполнено. - person ; 26.10.2011

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

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

export JVM_ARGS="-Xms1024m -Xmx1024m"

Ссылка на ссылку

person chaukssey    schedule 04.09.2011
comment
Есть идеи, почему нам нужно держать их в соотношении 1: 1 или 1: 1,5? - person ernesto; 25.10.2012

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

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

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

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

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

person Soumya Sandeep Mohanty    schedule 10.05.2011

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

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

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

person Leigh    schedule 09.10.2008

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

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

person Thorbjørn Ravn Andersen    schedule 19.05.2009
comment
Java WebStart постепенно прекращается. Я пока не знаю подходящей замены. - person Thorbjørn Ravn Andersen; 31.12.2018

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

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

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

person Nima Ganji    schedule 24.10.2020

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

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

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

person satish    schedule 04.04.2017

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

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

person Xiaogang    schedule 12.06.2017

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

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

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

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

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

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

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

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

person SoulWanderer    schedule 29.09.2010

Если эта ошибка возникает сразу после выполнения тестов junit, вам следует выполнить Build - ›Rebuild Project.

person kingarthur    schedule 28.05.2021

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

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

person nccc    schedule 11.11.2019

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

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

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

-Xmx512m -XX: MaxPermSize = 512m

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

Спасибо

person Antonin Dioulo    schedule 16.09.2020

Android Studio

Файл - ›Недействительные кеши и перезапуск решили для меня :)

person itzo    schedule 14.03.2021

Проблема с пространством кучи Java OOM также может возникнуть, когда ваш пул соединений с БД переполнен.

Я столкнулся с этой проблемой из-за того, что мой пул подключений Hikari (при обновлении до Spring boot 2.4. *) Был заполнен и больше не мог предоставлять подключения (все активные подключения все еще ожидают получения результатов из базы данных).

Проблема заключается в том, что некоторые из наших собственных запросов в репозиториях JPA содержат ORDER BY? # {# Pageable}, что требует очень много времени для получения результатов при обновлении.

Удален ORDER BY? # {# Pageable} из всех собственных запросов в репозиториях JPA, и проблема с пространством кучи OOM вместе с проблемой пула соединений была решена.

person Haranath Boggarapu    schedule 22.04.2021