У Quik закончилась память для объектов, без которых приложение не может работать

Обновлено: 21.11.2024

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

Учитывая эту ситуацию, что мне делать с этим ограничением?

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

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

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

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

30 ответов 30

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

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

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

Симптомы

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

Прежде чем мы расскажем об устранении неполадок с OutOfMemoryException , важно понять, что вызывает эту проблему. Вопреки мнению многих разработчиков, объем установленной оперативной памяти не влияет на вероятность возникновения OutOfMemoryException. 32-разрядная операционная система может адресовать 4 ГБ виртуального адресного пространства независимо от объема физической памяти, установленной в коробке. Из них 2 ГБ зарезервировано для операционной системы (память режима ядра) и 2 ГБ выделено для процессов пользовательского режима. 2 ГБ, выделенные для памяти режима ядра, совместно используются всеми процессами, но каждый процесс получает собственные 2 ГБ адресного пространства пользовательского режима. Все это предполагает, что вы не работаете с включенным переключателем /3gb.

32-разрядный процесс, работающий в 64-разрядной операционной системе, может обращаться к 4 ГБ памяти пользовательского режима, а 64-разрядный процесс, работающий в 64-разрядной операционной системе, может обращаться к 8 ТБ памяти пользовательского режима, поэтому OOM в 64-битной операционной системе маловероятен. В 32-разрядном процессе, работающем в 64-разрядной операционной системе, может возникнуть OOM, но обычно это не происходит, пока процесс не использует около 3 ГБ закрытых байтов.

Есть две причины, по которым вы можете увидеть состояние OOM.

  1. Ваш процесс использует много памяти (обычно более 800 МБ в 32-разрядной среде).
  2. Виртуальное адресное пространство фрагментировано, что снижает вероятность успешного выделения большого непрерывного пространства.

При возникновении OOM вы можете заметить один или несколько из следующих симптомов:

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

Обработка запросов может занять много времени.

В Internet Information Services (IIS) 7 вы можете использовать Устранение неполадок с невыполненными запросами с помощью трассировки в IIS 7 для устранения неполадок с длительными запросами.

Пользователи могут сообщать об ошибке в приложении из-за OOM.

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

Следующая информация описывает распространенные причины состояний OOM и решения по устранению каждой из этих причин.

Конкатенация строк

Фрагментация в управляемой куче

Сборщик мусора (GC) в управляемом приложении уплотняет кучи, чтобы уменьшить степень фрагментации. Однако можно закрепить объекты в управляемом приложении. Закрепленные объекты нельзя перемещать во время сжатия кучи. Это изменит адрес, по которому находится объект. Если приложение закрепляет большое количество объектов и/или закрепляет объекты в течение длительного времени, это может привести к фрагментации в управляемой куче. Это может привести к тому, что сборщик мусора будет чаще увеличивать управляемую кучу, что вызовет состояние OOM.

Фрагментация в пространстве виртуальных адресов (VA)

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

Фрагментация пространства виртуальных машин часто вызывается одним или несколькими из следующих сценариев:

Загрузка одних и тех же сборок в несколько доменов приложений.

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

Запуск приложения в рабочей среде с атрибутом отладки элемента, для которого задано значение true .

Использование сценариев в расширяемом языке таблиц стилей (XSL) преобразует или создает XmlSerializers .

В данном случае динамические сборки, вызванные сценариями Extensible Style Sheet Language Transformations (XSLT) или XmlSerializers .

Возвращает большие наборы данных

При использовании данных из базы данных или другого источника данных важно ограничить объем возвращаемых данных. Например, кэширование результата запроса, который возвращает всю таблицу базы данных, чтобы избежать затрат на получение частей данных из базы данных, когда это необходимо, не является хорошим подходом. Это может легко вызвать переполнение памяти и привести к состоянию OOM. Разрешение пользователю запустить аналогичный запрос — еще один распространенный способ создать ситуацию с нехваткой памяти. Например, вернуть всех сотрудников компании или всех клиентов в штате Техас с фамилией, начинающейся с буквы S.

Всегда ограничивайте объем данных, которые могут быть возвращены из базы данных. Не разрешайте такие запросы, как SELECT * FROM. . . потому что вы не можете контролировать, сколько данных отображается на вашей странице.

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

Запуск в производственной среде с включенной трассировкой

Трассировка должна быть отключена в производственной среде. Это можно сделать, установив для атрибута enable элемента значение false в файле web.config. Включение розничного развертывания с помощью также отключает трассировку в ваших приложениях.

Утечка нативных ресурсов

Многие управляемые ресурсы также используют собственные ресурсы. Поскольку GC не очищает собственные ресурсы, разработчик несет ответственность за реализацию и вызов метода Dispose для очистки собственных ресурсов. Если вы используете тип, реализующий интерфейс IDisposable, и не вызываете метод Dispose, вы рискуете утечкой собственных ресурсов и вызовом состояния OOM.

Эти объекты должны реализовывать интерфейс iDisposable, и вы должны вызывать метод Dispose для этих объектов, когда они вам больше не нужны.

macOS регулярно выводит диалоговое окно «Принудительный выход из приложений»:

В вашей системе закончилась память приложения.

Во избежание проблем с компьютером закройте все неиспользуемые приложения.

Как это возможно, если открыто всего несколько приложений?

8 ответов 8

По моему опыту, это происходит, когда на моем основном системном жестком диске заканчивается свободное место. Операционные системы используют жесткий диск для хранения дополнительной памяти, называемой «виртуальной памятью». (Мне определенно всегда хотелось, чтобы ОС могла просто резервировать достаточно места для себя, но она просто не может предсказать, сколько приложений мы будем запускать).

Кроме того, стоит отметить, что обычное использование Интернета теперь требует гораздо больше памяти, чем раньше. В мониторе активности вы заметите, что каждая отдельная вкладка и окно (каждая открытая веб-страница) — это отдельный процесс, занимающий значительную часть памяти. Кроме того, учитывайте всю рекламу, фильмы, flash, скрипты, плагины, панорамные видео и т. д., которые, как мы ожидаем, будут работать без сбоев. Новые ОС и новые веб-страницы просто используют много памяти, чтобы предоставить нам услуги, которые, как мы ожидаем, будут «просто работать» (например, синхронизация между устройствами, уведомления, автоматическое обновление и т. д. и т. д.).

Короче говоря, по моему опыту, обычно не бывает ни одного процесса, который внезапно занял бы огромный объем памяти (хотя виновником действительно может быть дырявая программа — например, Sketchup 2016 делает это со мной). Чаще всего это дополнительная функциональность, которую мы ожидаем от многих программ/веб-плагинов.

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

Два решения, которые мне подходят:

1) Открывайте меньше вкладок/страниц и программ одновременно. Закройте некоторые веб-страницы/программы, прежде чем открывать тяжелые приложения, такие как MS Office, Parallels, 3D CAD, программы Adobe и т. д.

2) Освободите больше места на системном жестком диске (например, переместите всю свою музыку и фотографии на другой диск), чтобы система могла справиться с типичными потребностями в виртуальной памяти. Для меня это означает, что моему диску ОС объемом 1 ТБ требуется > 20% свободного места (200 ГБ)! Ваши требования могут отличаться. Если вы работаете со старым ноутбуком Apple, iMac или Mini, OWC Data-Doubler — отличный способ добиться этого.

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

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

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

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

Как решить ошибку «Недостаточно памяти» в JavaScript

Самый быстрый способ решить эту проблему — увеличить лимит памяти Node. Начиная с Node.js v8, вы можете установить ограничение в МБ с помощью флага --max-old-space-size следующим образом:

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

В качестве альтернативы вы также можете установить флаг в переменной среды следующим образом:

Измените ограничения памяти Node.js в вашей среде

Если вы хотите изменить ограничения памяти Node.js для всей вашей среды, вам необходимо установить следующую переменную в файле конфигурации вашей среды. ( .bashrc , .bash_profile , иногда .zshrc и т. д.)

Добавьте эту строку в файл конфигурации:

Куча «npm install» не хватает памяти

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

Что вообще означает эта ошибка?

По умолчанию Node.js имеет ограничения по памяти, которые не позволяют программе потреблять слишком много памяти и вызывать сбой всей системы. Результаты различаются в зависимости от версии и системной архитектуры вашей системы (32-разрядная или 64-разрядная).

Ограничения памяти для разных версий Node.js

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

< td >2,01 ГБ
Версия узлаОграничение
15.0.1 4,03 ГБ
14.15.04,03 ГБ
13.14.0
12.19.02,01 ГБ
11.15.01,34 ГБ
10.15.31,34 ГБ
9.11.21,35 ГБ

Как видно из этой таблицы, в некоторых версиях лимиты по умолчанию увеличивались. 4 ГБ динамической памяти обычно достаточно для большинства случаев использования.

Вы можете проверить это самостоятельно, создав файл index.js со следующим кодом и запустив его с версией Node.js, для которой вы хотите узнать ограничение.

Как предотвратить нехватку памяти Node.js

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

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

Вот три альтернативных решения для сокращения потребления памяти, которые я использовал или с которыми сталкивался в какой-то момент.

Разделить обработку данных на более мелкие фрагменты

В некоторых случаях необходимо обрабатывать большие наборы данных. Например, вы написали средство импорта, которое берет данные из CSV-файла, очищает их и, наконец, добавляет в базу данных (это также известно как ETL: извлечение — преобразование — загрузка).

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

Взято из этого ответа StackOverflow, в котором более подробно объясняется, как это сделать с базой данных MongoDB.

Избегайте утечек памяти

Вашему приложению постоянно не хватает памяти, и увеличение лимита памяти только помогает выиграть время? Скорее всего, в вашем приложении есть утечки памяти.

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

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

Профилирование

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

В Node.js вы также можете использовать Chrome для отладки использования памяти, начиная с версии 6.3.0. Во-первых, вам нужно запустить приложение в режиме проверки:

Затем откройте chrome://inspect в Chrome и нажмите Открыть специальные инструменты DevTools для Node . Откроется новое окно отладки, которое автоматически подключится к вашему приложению Node.js.

Создавать процессы и перезапускать их, когда им не хватает памяти

Допустим, вы запускаете свою программу на компьютере с очень ограниченным объемом памяти, например, на Raspberry Pi.

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

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

Я нашел это интересным способом решения проблемы, но сам еще не сталкивался с прецедентом, в котором это было бы необходимо.

Заключение

В этой статье я постарался предоставить вам всю доступную информацию, необходимую для устранения ошибки «JavaScript Heap Out Of Memory».

Если вы хотите узнать больше о том, как работает JavaScript, я недавно написал эти две статьи об управлении памятью и цикле обработки событий:

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

Читайте оригинальную статью или другие интересные сообщения в блоге Феликса.

Внешний мониторинг

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

Удачной отладки для современных интерфейсных команд. Начните бесплатно отслеживать свое веб-приложение.

Читайте также: