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