Ошибка java.lang.OutOfMemoryError: превышен лимит накладных расходов GC

805

Я получаю это сообщение об ошибке при выполнении моих тестов JUnit:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Я знаю, что OutOfMemoryErrorтакое, но что означает ограничение по накладным расходам GC? Как я могу решить это?

Mnementh
источник
16
Это звучит очень интересно. Я хотел бы, чтобы кто-то мог опубликовать код, который генерирует это.
Буб
1
Я просто обнаружил проблему, которая приводит к чрезмерному использованию памяти, почти до предела кучи. Простое решение может состоять в том, чтобы просто выделить больше памяти кучи для Java-Engine (-Xmx), но это помогает, только если приложению требуется ровно столько памяти, сколько было установлено до ограничения кучи.
Мнемент
1
@Mnementh Я дал ответ здесь, проверьте, помогает ли это stackoverflow.com/questions/11091516/…
lulu
16
@SimonKuang Обратите внимание, что существует несколько OutOfMemoryErrorсценариев, для которых увеличение кучи не является допустимым решением: исчерпание собственных потоков и исчерпание perm gen (который отделен от кучи) являются двумя примерами. Будьте осторожны, делая слишком широкие заявления о OutOfMemoryErrors; есть неожиданно разнообразный набор вещей, которые могут вызвать их.
Тим
3
Как вы решили проблему?
Торстен Ниехес

Ответы:

764

Это сообщение означает, что по какой-то причине сборщик мусора занимает слишком много времени (по умолчанию 98% всего процессорного времени процесса) и восстанавливает очень мало памяти при каждом запуске (по умолчанию 2% кучи).

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

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

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

Ознакомьтесь с руководством по настройке Java GC, которое доступно для различных версий Java и содержит разделы об этой конкретной проблеме:

Йоахим Зауэр
источник
9
Было бы правильно обобщить ваш ответ следующим образом: «Это похоже на ошибку« Out of Java Heap space ». Добавьте больше памяти с -Xmx». ?
Тим Купер
58
@ Тим: Нет, это было бы неправильно. Хотя увеличение объема памяти может уменьшить проблему, вы должны также взглянуть на свой код и понять, почему он производит такое количество мусора и почему ваш код скользит чуть ниже отметки «недостаточно памяти». Это часто признак неработающего кода.
Иоахим Зауэр
8
Спасибо, похоже, Oracle на самом деле не очень хорош в переносе данных, они нарушили связь.
Йоахим Зауэр
151
Вы меня на "Спасибо, кажется, Oracle на самом деле не так хорош"
Роб Грант
3
@Guus: если в одной JVM запущено несколько приложений, то да, они могут легко влиять друг на друга. Трудно сказать, кто из них плохо себя ведет. Разделение приложений на отдельные JVM может быть самым простым решением.
Йоахим Зауэр
215

Цитата из статьи Oracle « Настройка виртуальной машины Java SE 6 HotSpot [tm]» :

Чрезмерное время GC и OutOfMemoryError

Параллельный сборщик сгенерирует OutOfMemoryError, если на сборку мусора уходит слишком много времени: если на сборку мусора уходит более 98% общего времени и восстанавливается менее 2% кучи, генерируется ошибка OutOfMemoryError. Эта функция предназначена для предотвращения запуска приложений в течение длительного периода времени при небольшом прогрессе или его отсутствии, поскольку куча слишком мала. При необходимости эту функцию можно отключить, добавив эту опцию -XX:-UseGCOverheadLimitв командную строку.

РЕДАКТИРОВАТЬ: похоже, кто-то может печатать быстрее, чем я :)

Дейв
источник
87
«Вы можете отключить это ...», но ОП, скорее всего, не должен этого делать.
Стивен С.
2
Можете ли вы сказать мне разницу между "-XX" и "-Xmx"? Я смог отключить его, используя опцию "-Xmx".
Сушил Джавади
19
Ответ на очень старый комментарий здесь, но ... @Bart В -XX:начале нескольких параметров командной строки находится своего рода флаг, указывающий, что этот параметр сильно зависит от ВМ и нестабилен (может быть изменен без уведомления в будущих версиях). В любом случае -XX:-UseGCOverheadLimitфлаг указывает виртуальной машине отключить проверку ограничения накладных расходов GC (фактически «выключает»), тогда как ваша -Xmxкоманда просто увеличила кучу. В последнем случае проверка издержек GC все еще выполняется , это звучит так, как будто большая куча решила проблемы с перебором GC в вашем случае (это не всегда помогает).
Анджей Дойл
1
В моем приложении (чтение большого файла Excel в Talend) это не сработало, и из объяснений других пользователей я понимаю, почему. Это просто отключает ошибку, но проблема сохраняется, и ваше приложение будет тратить большую часть своего времени на обработку GC. На нашем сервере было много оперативной памяти, поэтому я использовал рекомендации Виталия для увеличения размера кучи.
RobbZ
В конечном итоге вы получите эту ошибку, если ваше приложение интенсивно использует данные, очистка памяти и уклонение от утечки данных - лучший выход, но требует некоторого времени.
Pievis
89

Если вы уверены, что в вашей программе нет утечек памяти , попробуйте:

  1. Увеличьте размер кучи, например -Xmx1g.
  2. Включить параллельный коллектор с низкой паузой -XX:+UseConcMarkSweepGC.
  3. Повторно используйте существующие объекты, когда это возможно, чтобы сэкономить память.

При необходимости проверку лимита можно отключить, добавив эту опцию -XX:-UseGCOverheadLimitв командную строку.

Виталий Федоренко
источник
9
Я не согласен с третьим советом. Повторное использование существующих объектов не экономит память (не допускайте утечки старых объектов, экономьте память :-) Более того, «повторное использование существующего объекта» было практикой для снятия давления ГХ. Но это НЕ ВСЕГДА хорошая идея: с современным GC мы должны избегать ситуаций, когда старые объекты содержат новые, потому что это может нарушить некоторые предположения о локальности ...
mcoolive
@mcoolive: см. несколько надуманный пример в комментариях к stackoverflow.com/a/5640498/4178262 ниже; создание Listобъекта внутри цикла вызвало вызов GC 39 раз вместо 22 раз.
Марк Стюарт
45

Обычно это код. Вот простой пример:

import java.util.*;

public class GarbageCollector {

    public static void main(String... args) {

        System.out.printf("Testing...%n");
        List<Double> list = new ArrayList<Double>();
        for (int outer = 0; outer < 10000; outer++) {

            // list = new ArrayList<Double>(10000); // BAD
            // list = new ArrayList<Double>(); // WORSE
            list.clear(); // BETTER

            for (int inner = 0; inner < 10000; inner++) {
                list.add(Math.random());
            }

            if (outer % 1000 == 0) {
                System.out.printf("Outer loop at %d%n", outer);
            }

        }
        System.out.printf("Done.%n");
    }
}

Использование Java 1.6.0_24-b07 в 32-разрядной версии Windows 7.

java -Xloggc:gc.log GarbageCollector

Тогда посмотрите на gc.log

  • Сработало 444 раза, используя метод BAD
  • Сработало 666 раз, используя метод WORSE
  • Сработал 354 раза, используя метод ЛУЧШЕ

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

Майк
источник
12
Пожалуйста, поясните: когда вы говорите «Триггеры n раз», означает ли это, что обычный GC происходил n раз, или что ошибка «Превышен лимит накладных расходов GC», о которой сообщает OP, случалась n раз?
Джон Шнайдер
Я только что протестировал с использованием Java 1.8.0_91 и никогда не получал ошибку / исключение, а «Триггер n раз» был от подсчета количества строк в gc.logфайле. Мои тесты показывают гораздо меньшее количество раз, но меньшее количество «триггеров» для ЛУЧШИХ, и теперь BAD «хуже», чем WORST сейчас. Мои счета: плохо: 26, хуже: 22, лучше 21.
Марк Стюарт
Я просто добавил «WORST_YET» модификация , где я определяю List<Double> listв наружном контуре вместо до того внешнего цикла, и Срабатывает 39 мусора коллекции.
Марк Стюарт
36

Причина ошибки в соответствии с платформой Java [8], Руководство по устранению неполадок Standard Edition : (выделение и разрывы строк добавлены)

[...] «Превышен лимит накладных расходов GC» означает, что сборщик мусора работает все время, а Java-программа продвигается очень медленно.

После сборки мусора, если Java-процесс тратит более чем приблизительно 98% своего времени на сборку мусора, и если он восстанавливает менее 2% кучи и выполняет до сих пор последние 5 (постоянная времени компиляции) подряд коллекции, то java.lang.OutOfMemoryErrorбросается. [...]

  1. Увеличьте размер кучи, если текущей кучи недостаточно.
  2. Если вы все еще получаете эту ошибку после увеличения кучи памяти, используйте инструменты профилирования памяти, такие как MAT (инструмент анализа памяти), Visual VM и т. Д., И исправьте утечки памяти.
  3. Обновите версию JDK до последней версии (1.8.x) или хотя бы 1.7.x и используйте алгоритм G1GC. , Цель пропускной способности для G1 GC - 90% времени приложения и 10% времени сбора мусора
  4. Помимо установки кучи памяти с помощью - Xms1g -Xmx2g, попробуйте

    -XX:+UseG1GC -XX:G1HeapRegionSize=n -XX:MaxGCPauseMillis=m  
    -XX:ParallelGCThreads=n -XX:ConcGCThreads=n

Посмотрите еще несколько связанных вопросов, касающихся G1GC

Равиндра Бабу
источник
29

Просто увеличьте размер кучи, установив эту опцию в

Выполнить → Выполнить настройки → Аргументы → Аргументы виртуальной машины

-Xms1024M -Xmx2048M

Xms - для минимального лимита

Xmx - для максимального лимита

chopss
источник
2
Приложения для Android не имеют argumentsвкладки ... что мы должны сделать, чтобы достичь этого?
Blaze Tama
3
Для какого инструмента этот ответ? Это был не вопрос Затмения.
Майкл Пифель
3
Там нет "минимального лимита". -Xms - это начальный размер.
Диего
1
Каков максимальный максимальный предел, который может быть установлен ??
JPerk
14

Для меня сработали следующие шаги:

  1. Открыть eclipse.iniфайл
  2. + Изменить

    -Xms40m
    -Xmx512m

    в

    -Xms512m
    -Xmx1024m
  3. Перезапустите Eclipse

Посмотреть здесь

Сунил Кумар Саху
источник
самый простой способ решить эту проблему. Спасибо :)
Хамза
1
файл eclipse.ini в jdev?
Абхинаба Басу
проблемы не решены, даже если конфигурация была изменена на это.
zionpi
1
ОП не задавал вопрос «Затмения».
Майкл Пифель
1
Этот «ответ» не отвечает на вопрос выше.
Freitags
13

попробуй это

открыть build.gradleфайл

  android {
        dexOptions {
           javaMaxHeapSize = "4g"
        }
   }
alicanozkara
источник
Отлично работает для симулятора. Есть идеи, как это влияет на реальные устройства? т.е. это хорошая идея или это просто маскировка проблемы? Спасибо.
Джошуа Пинтер
11

Следующее сработало для меня. Просто добавьте следующий фрагмент:

android {
        compileSdkVersion 25
        buildToolsVersion '25.0.1'

defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 10
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
dexOptions {
        javaMaxHeapSize "4g"
    }
}
Hoshouns
источник
Да, при использовании Gradle :)
Алекс
4
Как ты вообще мог подумать, что это решение его вопроса вообще ? Вы можете установить размер кучи для 4g , который является полностью произвольным в Gradle конфигурации для Android Facepalm .
Джулиан Л.
7

увеличьте javaMaxHeapsize в вашем файле build.gradle (модуль: приложение)

dexOptions {
    javaMaxHeapSize "1g"
}

(добавить эту строку в Gradle)

 dexOptions {
        javaMaxHeapSize "4g"
    }
Саи Гопи Н
источник
3

Описание размера кучи Java (xms, xmx, xmn)

-Xms size in bytes

Example : java -Xms32m

Устанавливает начальный размер кучи Java. Размер по умолчанию - 2097152 (2 МБ). Значения должны быть кратны и превышать 1024 байта (1 КБ). (Флаг -server увеличивает размер по умолчанию до 32M.)

-Xmn size in bytes

Example : java -Xmx2m

Устанавливает начальный размер кучи Java для поколения Eden. Значением по умолчанию является 640K. (Флаг -server увеличивает размер по умолчанию до 2M.)

-Xmx size in bytes

Example : java -Xmx2048m

Устанавливает максимальный размер, до которого может расти куча Java. Размер по умолчанию составляет 64M. (Флаг -server увеличивает размер по умолчанию до 128 МБ.) Максимальный предел кучи составляет около 2 ГБ (2048 МБ).

Форматирование аргументов памяти Java (xms, xmx, xmn)

При установке размера кучи Java вы должны указать аргумент памяти, используя одну из букв «m» или «M» для MB, или «g» или «G» для GB. Ваши настройки не будут работать, если вы укажете «МБ» или «ГБ». Допустимые аргументы выглядят так:

-Xms64m или -Xms64M -Xmx1g или -Xmx1G Можно также использовать 2048 МБ для указания 2 ГБ. Также убедитесь, что вы просто используете целые числа при указании аргументов. Использование -Xmx512m является допустимым параметром, но -Xmx0.5g вызовет ошибку.

Эта ссылка может быть полезна для кого-то.

Феникс
источник
2

Вы также можете увеличить выделение памяти и размер кучи, добавив это в свой gradle.propertiesфайл:

org.gradle.jvmargs=-Xmx2048M -XX\:MaxHeapSize\=32g

Это не должно быть 2048M и 32g, сделайте его таким большим, как вы хотите.

Джон Доу
источник
2

Решено:
Просто добавьте
org.gradle.jvmargs=-Xmx1024m
в
gradle.properties
и если она не существует, создайте его.

reza_khalafi
источник
0

Я работаю в Android Studio и столкнулся с этой ошибкой при попытке создать подписанный APK для выпуска. Я смог создать и протестировать отладочный APK без проблем, но как только мне захотелось создать релизный APK, процесс сборки будет выполняться несколько минут подряд, а затем в конце завершится с сообщением об ошибке «Ошибка java.lang.OutOfMemoryError: GC». превышен лимит накладных расходов ". Я увеличил размеры кучи для виртуальной машины и компилятора Android DEX, но проблема осталась. Наконец, после многих часов и кружек кофе выяснилось, что проблема была в моем файле уровня приложения «build.gradle» - у меня был параметр «minifyEnabled» для типа сборки выпуска, установленный в «false», в результате чего работали компоненты Proguard. в коде, который еще не прошел процесс сжатия кода (см. https://developer.android.). Я изменил параметр 'minifyEnabled' на 'true' и сборка релиза была выполнена как мечта :)

Короче говоря, мне пришлось изменить файл уровня приложения build.gradle с: // ...

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.sign_config_release
    }
    debug {
        debuggable true
        signingConfig signingConfigs.sign_config_debug
    }
}

//...

в

    //...

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.sign_config_release
    }
    debug {
        debuggable true
        signingConfig signingConfigs.sign_config_debug
    }
}

//...
Алекс Иван Ховард
источник
0

Чтобы увеличить размер кучи в IntelliJ IDEA, выполните следующие инструкции. Это сработало для меня.

Для пользователей Windows,

Перейдите в место, где установлена ​​IDE, и выполните поиск следующего.

idea64.exe.vmoptions

Отредактируйте файл и добавьте следующее.

-Xms512m
-Xmx2024m
-XX:MaxPermSize=700m
-XX:ReservedCodeCacheSize=480m

Вот и все !!

Дулит Де Коста
источник
0

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

Вы также можете внести изменения в кучу Java, открыв cmd-> set _java_opts -Xmx2g
2g (2 гигабайта) в зависимости от сложности вашей программы

попробуйте использовать менее постоянные и временные переменные

введите описание изображения здесь

Рахул Джайн
источник
-1

Вам нужно увеличить размер памяти в Jdeveloper, перейти в setDomainEnv.cmd .

set WLS_HOME=%WL_HOME%\server    
set XMS_SUN_64BIT=**256**
set XMS_SUN_32BIT=**256**
set XMX_SUN_64BIT=**3072**
set XMX_SUN_32BIT=**3072**
set XMS_JROCKIT_64BIT=**256**
set XMS_JROCKIT_32BIT=**256**
set XMX_JROCKIT_64BIT=**1024**
set XMX_JROCKIT_32BIT=**1024**

if "%JAVA_VENDOR%"=="Sun" (
    set WLS_MEM_ARGS_64BIT=**-Xms256m -Xmx512m**
    set WLS_MEM_ARGS_32BIT=**-Xms256m -Xmx512m**
) else (
    set WLS_MEM_ARGS_64BIT=**-Xms512m -Xmx512m**
    set WLS_MEM_ARGS_32BIT=**-Xms512m -Xmx512m**
)

а также

set MEM_PERM_SIZE_64BIT=-XX:PermSize=**256m**
set MEM_PERM_SIZE_32BIT=-XX:PermSize=**256m**

if "%JAVA_USE_64BIT%"=="true" (
    set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT%
) else (
    set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT%
)

set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=**1024m**
set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=**1024m**
Шаши
источник
4
Эти настройки относятся только к вашей локальной IDE. Это не будет работать для среды Prod.
Фэн
-1

В Netbeans может быть полезно создать максимальный размер кучи. Перейдите в Run => Set Configuration Configuration => Customize . В появившемся окне « Выполнить» откройте « Параметры виртуальной машины» и заполните -Xms2048m -Xmx2048m. Это может решить проблему размера кучи.

Сяоган
источник
-1

Перезагрузка моего MacBook исправила эту проблему для меня.

Томас
источник
-1

Я не знаю, актуально ли это до сих пор или нет, но просто хочу поделиться тем, что сработало для меня.

Обновите версию kotlin до последней доступной. https://blog.jetbrains.com/kotlin/category/releases/

и это сделано.

androidStud
источник