Як боротися з помилкою "java.lang.OutOfMemoryError: Пробіг у купі Java"?


416

Я пишу заявку Swing на стороні клієнта (графічний дизайнер шрифтів) на Java 5 . Останнім часом я стикаюся з java.lang.OutOfMemoryError: Java heap spaceпомилками, оскільки не буду консервативним щодо використання пам'яті. Користувач може відкривати необмежену кількість файлів, а програма зберігає відкриті об'єкти в пам'яті. Після швидкого дослідження я виявив Ергономіку у віртуальній машині 5.0 Java та ін., Які говорять на машині Windows, JVM за замовчуванням максимум розміру купи 64MB.

З огляду на таку ситуацію, як я маю поводитися з цим обмеженням?

Я міг би збільшити максимальний розмір купи за допомогою параметра командного рядка до Java, але це вимагатиме з'ясування доступної оперативної пам’яті та написання програми запуску чи сценарію. Крім того, збільшення до деякого кінцевого максимуму в кінцевому рахунку не позбудеться проблеми.

Я міг би переписати частину свого коду, щоб зберегти об'єкти для файлової системи часто (використання бази даних - це одне і те ж), щоб звільнити пам'ять. Це може спрацювати, але, мабуть, теж багато роботи.

Якщо ви можете вказати мені на деталі вищезазначених ідей або на деякі альтернативи, такі як автоматична віртуальна пам'ять, динамічно збільшуючи розмір купи , це буде чудово.


Максимальний розмір купи за замовчуванням - 64 Мб, починаючи з J2SE 5.0. Для отримання інформації про J2SE 8.0 див. "Ергономіка сміттєзбірника " на docs.oracle.com/javase/8/docs/technotes/guides/vm/… .
Енді Томас

Якщо ви приземлилися тут, оскільки кожне запитання про ОМП є придушеним до цього, переконайтеся, що ви також перевірили: stackoverflow.com/questions/299659/… Він пропонує рішення для очищення посилань на пам'ять "вчасно" перед OOM. SoftReferences може бути інструментом, який вирішує вашу фактичну проблему.
Стів Штейнер

Відповіді:


244

Зрештою, у вас завжди є обмежений максимум купівлі, яку ви можете використовувати незалежно від того, на якій платформі ви працюєте. У Windows 32 біт це близько 2GB(не конкретно купи, а загальний об'єм пам'яті за процес). Просто так трапляється, що Java вирішує зменшити за замовчуванням менше (мабуть, таким чином, щоб програміст не міг створювати програми, що мають втечене розподілення пам'яті, не стикаючись з цією проблемою і не потребуючи точно вивчити, що вони роблять).

Отже, з огляду на наявність декількох підходів, які ви можете використати, щоб визначити, який об'єм пам'яті вам потрібен, або зменшити об'єм пам'яті, який ви використовуєте. Однією поширеною помилкою мов, зібраних зі сміттям, таких як Java або C #, є те, щоб зберігати посилання на об'єкти, якими ви більше не користуєтесь, або виділяти багато об'єктів, коли ви можете замість цього використовувати їх повторно . Поки об’єкти мають посилання на них, вони продовжуватимуть використовувати кучу простору, оскільки збирач сміття не буде їх видаляти.

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

Якщо ви визначите, що ви виділяєте ці об'єкти з якоїсь причини, і вам потрібно тримати навколо посилань (залежно від того, що ви робите, це може бути так), вам просто потрібно буде збільшити максимальний розмір купи під час запуску програми. Однак, як тільки ви зробите профілювання пам'яті і зрозумієте, як виділяються ваші об'єкти, ви повинні мати краще уявлення про те, скільки пам'яті вам потрібно.

Як правило, якщо ви не можете гарантувати, що ваша програма буде працювати в певному обсязі пам'яті (можливо, залежно від розміру вводу), ви завжди будете стикатися з цією проблемою. Тільки після вичерпання всього цього вам потрібно буде вивчити кешування об'єктів на диск і т. Д. У цей момент у вас повинен бути дуже вагомий привід сказати "мені потрібна Xgb пам'яті" для чогось, і ви не можете обійти це шляхом вдосконалення ваші алгоритми чи схеми розподілу пам'яті. Як правило, це стосується лише алгоритмів, що працюють на великих наборах даних (наприклад, база даних або якась програма наукового аналізу), а потім такі корисні методи, як кешування і пам'ять, нанесені на IO, стають корисними.


6
OpenJDK і OracleJDK укомплектовані профілером - jvisualvm. Якщо ви хочете більше зручностей, я пропоную комерційний Yourkit.
Петро Гладких

121

Запустіть Java за допомогою параметра командного рядка -Xmx, який встановлює максимальний розмір купи.

Детальніше дивіться тут .


3
Як встановити цей параметр назавжди? Тому що я використовую команду 'gradlew assemble'.
Dr.jacky

2
Виконати-> Запустити конфігурації-> Клацніть на аргументи-> всередині аргументів VM -Xms1g -Xmx2g
Arayan Singh

2
Це справжня відповідь.
nccc

85

Ви можете вказати на проект, скільки місця купи хоче ваш проект

Далі йдеться про Eclipse Helios / Juno / Kepler :

Клацніть правою кнопкою миші на

 Run As - Run Configuration - Arguments - Vm Arguments, 

потім додайте це

-Xmx2048m

1
привіт bighostkim та cuongHuyTo, де "Аргументи" .. я можу побачити до запуску конфігурації. Будь ласка, скажіть мені. Моя потреба завантажити та зберігати майже 2000 контактів з Gmail. Це збої через виключення з пам'яті
AndroidRaji

@AndroiRaji: клацніть правою клавішею миші на класі Java, який має основний запуск (тобто "загальнодоступний статичний недійсний основний (String [] аргументи)") ", а потім виберіть" Запустити як - запустити конфігурацію ". Тоді "Аргументи" - це вкладка відразу після Головного (ви бачите вкладки "Основні", "Аргументи", "JRE", "Класовий шлях", "Джерело", "Навколишнє середовище", "Загальні".
CuongHuyTo

47

Збільшення розміру купи - це не «виправлення», це «штукатурка», 100% тимчасова. Він знову вріжеться десь в іншому місці. Щоб уникнути цих проблем, пишіть код високої продуктивності.

  1. Використовуйте локальні змінні, де це можливо.
  2. Переконайтесь, що ви вибрали правильний об’єкт (EX: Вибір між String, StringBuffer та StringBuilder)
  3. Використовуйте хорошу систему коду для вашої програми (EX: Використання статичних змінних VS нестатичних змінних)
  4. Інші речі, які можуть працювати на вашому коді.
  5. Спробуйте рухатися з багатогранною РІЗНОЮ

Це так правда. Я намагаюся виправити одну проблему, де я отримую OOM на AWT-потоці, але якщо я використовую різні нові потоки, я не отримую проблеми OOM. Все, що я можу знайти в Інтернеті - це збільшити розмір купи для потоку AWT.
Ашиш

@Ash: Так, вирішіть основну проблему, а не шукайте штукатурки.
Лимонний сік

Збір сміття та підхід до управління пам’яттю на Яві повинен був вирішити всі ці ускладнення, пов'язані з утилізацією балоків своїх попередників. -структури, які прибираються якнайшвидше
Давос

31

Великий застереження ---- в моєму кабінеті ми виявили, що (на деяких машинах з вікнами) ми не можемо виділити більше 512 м для кучі Java. Це виявилося завдяки антивірусному продукту Касперського, встановленому на деяких із цих машин. Після видалення цього продукту AV ми виявили, що ми можемо виділити щонайменше 1,6 гбіт, тобто -Xmx1600m(m обов'язковий для інших, це призведе до чергової помилки "Занадто мала початкова купа").

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


22

Аргументи В.М. працювали на мені в затемненні. Якщо ви використовуєте затемнення версії 3.4, виконайте наступне

перейдіть, Run --> Run Configurations -->а потім виберіть проект під Maven build -> потім виберіть вкладку "JRE" -> та введіть -Xmx1024m.

Можна також Run --> Run Configurations --> select the "JRE" tab -->ввести -Xmx1024m

Це повинно збільшити купу пам'яті для всіх збірок / проектів. Вищенаведений об'єм пам'яті - 1 Гб. Ви можете оптимізувати так, як вам потрібно.


18

Так, -Xmxви можете налаштувати більше пам’яті для свого JVM. Щоб бути впевненим, що ви не просочуєтесь і не витрачаєте пам'ять. Візьміть кучу сміття і використовуйте аналізатор пам'яті Eclipse для аналізу споживання вашої пам'яті.


JVMJ9VM007E Нерозпізнаний варіант командного рядка: -Xmx Не вдалося створити віртуальну машину Java. Downvote
Філіп Рего

17

Я хотів би додати рекомендації зі статті про зйомки неполадок у Oracle .

Виняток у потоці ім'я теми: java.lang.OutOfMemoryError: Куповий простір Java

Повідомлення з детальним повідомленням у просторі купи Java вказує, що об'єкт не може бути виділений у купі Java. Ця помилка не обов'язково означає витік пам'яті

Можливі причини:

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

  2. Додаток ненавмисно містить посилання на об’єкти , і це не дозволяє об'єктам збирати сміття.

  3. Надмірне використання фіналізаторів .

Ще одне потенційне джерело цієї помилки виникає із програмами, які надмірно використовують фіналізатори. Якщо в класі є метод доопрацювання, об'єкти цього типу не мають регенерованого простору під час збору сміття

Після вивезення сміття об’єкти ставлять у чергу для доопрацювання , що відбувається в більш пізній час. фіналізатори виконуються демоновою ниткою, яка обслуговує чергу завершення. Якщо нитка фіналізатора не може йти в ногу з чергою на завершення, тоді купа Java може заповнитися, і цей виняток OutOfMemoryError буде викинутий.

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


9

Виконайте нижче кроки:

  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. Перезавантажте свій tomcat


8

Я читав десь ще, що ви можете спробувати - зловити java.lang.OutOfMemoryError та на блоці вилову ви можете звільнити всі ресурси, які, на вашу думку, можуть використовувати багато пам’яті, тісні зв’язки і так далі, а 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();

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

6
@mwangi Calling System.gc () безпосередньо з коду, як правило, погана ідея. Це просто пропозиція JVM про те, що GC слід виконувати, але абсолютно немає гарантії, що він буде виконаний.

7

Простий спосіб вирішити 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: 1,5?
ernesto

7

За замовчуванням для розробки JVM використовує невеликий розмір і невеликий конфігурацію для інших функцій, пов'язаних з продуктивністю. Але для виробництва ви можете настроїтись, наприклад (крім того, що може існувати конкретний конфігураційний сервер Application Server) -> (Якщо ще не вистачає пам'яті для задоволення запиту, і купа вже досягла максимального розміру, відбудеться 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.


7

Я стикався з тією ж проблемою, що стосується розміру купи Java.

У мене є два рішення, якщо ви використовуєте java 5 (1.5).

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

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

Я думаю, це спрацює ...


7

Якщо вам потрібно відстежувати споживання пам’яті під час виконання, java.lang.managementпакет пропонує MBeansвикористовувати для моніторингу пулів пам’яті у вашій машині управління (наприклад, простір Едена, генерація штату тощо), а також поведінку збору сміття.

Вільний простір для купівлі, повідомлений цими MBeans, сильно відрізнятиметься в залежності від поведінки GC, особливо якщо ваша програма генерує безліч об'єктів, які згодом виходять з GC. Один з можливих підходів - це відслідковувати вільний простір у купі після кожного повного GC, який ви, можливо, зможете використати для прийняття рішення про звільнення пам'яті шляхом збереження об'єктів.

Зрештою, найкраще обмежити збереження пам’яті наскільки це можливо, в той час як продуктивність залишається прийнятною. Як зазначалося в попередньому коментарі, пам’ять завжди обмежена, але ваш додаток має мати стратегію боротьби з виснаженням пам'яті.


5

Зауважте, що якщо вам це потрібно в ситуації розгортання, подумайте про використання Java WebStart (з версією "ondisk", а не мережевою - можливо в Java 6u10 і пізніших версіях), оскільки це дозволяє вказувати різні аргументи JVM в кросі платформенний шлях.

В іншому випадку вам знадобиться спеціальна панель запуску для операційної системи, яка встановлює необхідні аргументи.


Java WebStart припиняється. Я ще не знаю про підходящу заміну.
Thorbjørn Ravn Andersen

1

Якщо ця проблема трапляється в Wildfly 8 та JDK1.8, тоді нам потрібно вказати параметри MaxMetaSpace замість параметрів PermGen.

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

Для отримання додаткової інформації перегляньте Випуск Wildfly Heap


1

Щодо мережевих бобів, ви можете встановити максимальний розмір купи, щоб вирішити проблему.

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


1

Якщо ви продовжуєте розподіляти та зберігати посилання на об’єкт, ви заповнить будь-який обсяг пам'яті, який у вас є.

Один із варіантів - зробити прозорий файл закритим і відкритим, коли вони переключаються на вкладки (ви тримаєте лише вказівник на файл, а коли користувач перемикає вкладку, ви закриваєте та очищаєте всі об'єкти ... це зробить зміну файлу повільніше ... але ...) і, можливо, зберігати в пам'яті лише 3 або 4 файли.

Інша річ, яку ви повинні зробити, це коли користувач відкриває файл, завантажує його та перехоплює будь-який OutOfMemoryError, тоді (оскільки неможливо відкрити файл) закрийте цей файл, очистіть його об'єкти та попередить користувача, що він повинен закрити невикористаний файли.

Ваша ідея щодо динамічного розширення віртуальної пам’яті не вирішує проблему, оскільки машина обмежена ресурсами, тому вам слід бути обережними та керувати проблемами пам’яті (або, принаймні, бути обережними з ними).

Кілька підказок, які я бачив із витоком пам’яті, це:

-> Майте на увазі, що якщо ви щось помістите у колекцію, а потім забудете про неї, у вас все-таки є чіткі посилання на неї, тому анулюйте колекцію, очистіть її чи зробіть щось із нею ... якщо ні, ви знайдете витоку пам'яті важко знайти.

-> Можливо, використання колекцій зі слабкими посиланнями (слабкі карти) може допомогти з проблемами пам'яті, але ви повинні бути обережні з нею, тому що ви можете виявити, що об'єкт, який ви шукаєте, зібраний.

-> Ще одна ідея, яку я знайшов, - розробити стійку колекцію, що зберігається на найменш використаних та прозоро завантажених об'єктах бази даних. Це, мабуть, найкращий підхід ...


0

Якщо все інше не вдається, окрім збільшення розміру максимуму купи, спробуйте також збільшити розмір свопу. На сьогодні для Linux відповідні інструкції можна знайти на https://linuxize.com/post/create-a-linux-swap-file/ .

Це може допомогти, якщо ви, наприклад, збираєте щось велике у вбудовану платформу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.