Java.lang.OutOfMemoryError: превышен верхний предел GC

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

Согласно Sun, ошибка происходит "если слишком много времени тратится на сбор мусора: если более 98% общего времени тратится на сбор мусора и восстанавливается менее 2% кучи, OutOfMemoryError будет быть брошенным.".

По-видимому, можно использовать командную строку для передачи аргументов JVM для

  • Увеличение размера кучи с помощью "-Xmx1024m" (или более) или
  • Отключить проверку ошибок в целом, используя "-XX: -UseGCOverheadLimit".

Первый подход работает отлично, второй заканчивается в другом java.lang.OutOfMemoryError, на этот раз о куче.

Итак, вопрос: есть ли какая-либо программная альтернатива этому, для конкретного варианта использования (т.е. нескольких небольших объектов HashMap)? Например, если я использую метод clear() HashMap, проблема исчезает, но также сохраняются данные, хранящиеся в HashMap!: -)

Проблема также обсуждается в qaru.site/info/14650/...

Ответ 1

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

  • Укажите больше памяти, как вы упомянули, попробуйте что-то между собой, например -Xmx512m first
  • Работа с меньшими партиями объектов HashMap для обработки сразу, если это возможно.
  • Если у вас много повторяющихся строк, используйте String.intern(), прежде чем помещать их в HashMap
  • Используйте конструктор HashMap(int initialCapacity, float loadFactor) для настройки вашего случая

Ответ 2

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

dexOptions {
        javaMaxHeapSize "4g"
}

К вашему build.gradle:

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.1'

    defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        multiDexEnabled true
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {

    }

    dexOptions {
        javaMaxHeapSize "4g"
    }
}

Ответ 3

@takrl: настройка по умолчанию для этой опции:

java -XX:+UseConcMarkSweepGC

что означает, что эта опция по умолчанию не активна. Поэтому, когда вы говорите, что использовали опцию "+XX:UseConcMarkSweepGC" Я предполагаю, что вы использовали этот синтаксис:

java -XX:+UseConcMarkSweepGC

что означает, что вы явно активировали эту опцию. Для правильного синтаксиса и настроек по умолчанию Java HotSpot VM Options @this документ

Ответ 4

Для записи у нас была та же проблема сегодня. Мы исправили это с помощью этой опции:

-XX:-UseConcMarkSweepGC

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

Ответ 5

Ummm... вам нужно будет:

  • Полностью переосмыслите свой алгоритм и структуры данных, чтобы ему не нужны все эти маленькие HashMaps.

  • Создайте фасад, который позволяет вам размещать эти HashMaps в-и-из памяти по мере необходимости. Простым LRU-кешем может быть только билет.

  • Домен, доступный для JVM. При необходимости даже покупка большего количества ОЗУ может быть самым быстрым решением CHEAPEST, если у вас есть управление машиной, на которой размещается этот зверь. Сказав это: я, как правило, не поклонник решений "бросить больше аппаратных средств", особенно если альтернативное алгоритмическое решение можно придумать в разумные сроки. Если вы продолжаете бросать больше аппаратного обеспечения при каждой из этих проблем, вы вскоре столкнетесь с законом уменьшения отдачи.

Что вы на самом деле пытаетесь сделать в любом случае? Я подозреваю, что есть лучший подход к вашей реальной проблеме.

Ответ 6

Используйте альтернативную реализацию HashMap (Trove). Стандартный Java HashMap имеет > 12x служебных данных памяти. Здесь можно прочитать подробности здесь.

Ответ 7

Не сохраняйте всю структуру в памяти, ожидая ее завершения.

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

Если все сделано правильно, ваш алгоритм не должен даже замечать изменение - правильно здесь означает использовать класс для представления таблицы, даже предоставляя ему метод put (key, value) и get (key), как хэш-карту.

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

Ответ 8

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

Ответ 9

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

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

Ответ 10

Если у вас java8, и вы можете использовать G1 Garbage Collector, затем запустите приложение с помощью

 -XX:+UseG1GC -XX:+UseStringDeduplication

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

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

Дополнительная информация:
https://blog.codecentric.de/en/2014/08/string-deduplication-new-feature-java-8-update-20-2/ http://java-performance.info/java-string-deduplication/

Ответ 11

Исправить утечки памяти в вашем приложении с помощью таких профильных инструментов, как eclipse MAT или VisualVM

С JDK 1.7.x или более поздними версиями используйте G1GC, , который тратит 10% на сборку мусора, в отличие от 2% в других алгоритмах GC.

Помимо настройки памяти кучи с -Xms1g -Xmx2g, попробуйте `

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

Посмотрите oracle статью для точной настройки этих параметров.

Некоторые вопросы, связанные с G1GC в SE:

Сбор и сбор мусора Java 7 (JDK 7) в G1

Сбор мусора Java G1 в производстве

Агрессивная стратегия сборщика мусора

Ответ 12

В случае ошибки:

"Внутренняя ошибка компилятора: java.lang.OutOfMemoryError: верхний предел GC превышен на java.lang.AbstractStringBuilder"

увеличить пространство кучи java до 2 ГБ, т.е. -Xmx2g.

Ответ 13

Вам нужно увеличить размер памяти в 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
)
and

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

Ответ 14

Для этого используйте ниже код в вашем приложении gradle файл под закрытием Android.

dexOptions {   javaMaxHeapSize "4g" }

Ответ 15

Для моего случая увеличение памяти с помощью опции -Xmx было решением.

У меня был файл 10g, читаемый в java, и каждый раз, когда я получал ту же ошибку. Это произошло, когда значение в столбце RES в top достигло значения, установленного в опции -Xmx. Затем, увеличив память с помощью опции -Xmx, все пошло нормально.

Был еще один момент. Когда я установил JAVA_OPTS или CATALINA_OPTS в свою учетную запись пользователя и снова увеличил объем памяти, я получил ту же ошибку. Затем я напечатал значение этих переменных окружения в моем коде, который дал мне разные значения, чем то, что я установил. Причина в том, что Tomcat был корнем для этого процесса, а затем, поскольку я не был su-doer, я попросил администратора увеличить память в catalina.sh в Tomcat.

Ответ 16

Это помогло мне избавиться от этой ошибки. Эта опция отключает -XX: + DisableExplicitGC