java.lang.OutOfMemoryError: limite de sobrecarga do GC excedido

Eu estou recebendo esse erro em um programa que cria vários (centenas de milhares) objects HashMap com algumas inputs de texto (15-20) cada. Essas cadeias têm que ser coletadas (sem se dividirem em quantidades menores) antes de serem submetidas a um database.

De acordo com a Sun, o erro ocorre “se muito tempo estiver sendo gasto na garbage collection: se mais de 98% do tempo total for gasto na garbage collection e menos de 2% do heap for recuperado, um OutOfMemoryError será lançado. “.

Aparentemente, pode-se usar a linha de comando para passar argumentos para a JVM para

  • Aumentando o tamanho do heap via “-Xmx1024m” (ou mais) ou
  • Desativando a verificação de erros, via “-XX: -UseGCOverheadLimit”.

A primeira abordagem funciona bem, a segunda acaba em outro java.lang.OutOfMemoryError, desta vez sobre o heap.

Então, pergunta: existe alguma alternativa programática para isso, para o caso de uso específico (isto é, vários pequenos objects HashMap)? Se eu usar o método HashMap clear (), por exemplo, o problema desaparece, assim como os dados armazenados no HashMap! 🙂

O problema também é discutido em um tópico relacionado no StackOverflow.

Você está essencialmente sem memory para executar o processo sem problemas. Opções que vêm à mente:

  1. Especifique mais memory como você mencionou, tente algo entre como -Xmx512m primeiro
  2. Trabalhar com lotes menores de objects HashMap para processar de uma vez, se possível
  3. Se você tiver muitas cadeias duplicadas, use String.intern() nelas antes de colocá-las no HashMap
  4. Use o HashMap(int initialCapacity, float loadFactor) para ajustar seu caso

O seguinte funcionou para mim. Basta adicionar o seguinte trecho:

 dexOptions { javaMaxHeapSize "4g" } 

Para o seu 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" } } 

@takrl: A configuração padrão para esta opção é:

 java -XX:+UseConcMarkSweepGC 

o que significa que esta opção não está ativa por padrão. Então, quando você diz que usou a opção ” +XX:UseConcMarkSweepGC “, presumo que você esteja usando esta syntax:

 java -XX:+UseConcMarkSweepGC 

o que significa que você estava explicitamente ativando essa opção. Para obter as configurações padrão e de syntax corretas das opções de Java HotSpot VM Options @ neste documento

Para o registro, tivemos o mesmo problema hoje. Nós consertamos usando esta opção:

 -XX:-UseConcMarkSweepGC 

Aparentemente, isso modificou a estratégia usada para garbage collection, o que fez com que o problema desaparecesse.

Ummm … você precisará:

  1. Repense completamente seu algoritmo e estruturas de dados, de modo que ele não precise de todos esses pequenos HashMaps.

  2. Crie uma fachada que permita que você pague os HashMaps dentro e fora da memory conforme necessário. Um simples cache LRU pode ser apenas o ticket.

  3. Acima a memory disponível para a JVM. Se necessário, até mesmo comprar mais memory RAM pode ser a solução mais rápida e barata, se você tiver o gerenciamento da máquina que hospeda essa fera. Tendo dito isto: eu geralmente não sou um fã das soluções “lance mais hardware nisso”, especialmente se uma solução algorítmica alternativa puder ser pensada dentro de um prazo razoável. Se você continuar jogando mais hardware em cada um desses problemas, logo encontrará a lei dos retornos decrescentes.

O que você está realmente tentando fazer de qualquer maneira? Eu suspeito que há uma abordagem melhor para o seu problema real.

Use a implementação alternativa do HashMap ( Trove ). O Java HashMap padrão possui uma sobrecarga de memory> 12x. Pode-se ler detalhes aqui .

Não armazene toda a estrutura na memory enquanto espera chegar ao fim.

Grave resultados intermediários em uma tabela temporária no database em vez de hashmaps – funcionalmente, uma tabela de database é equivalente a um hashmap, ou seja, ambos suportam access com chave aos dados, mas a tabela não é vinculada à memory, portanto use uma tabela indexada aqui os hashmaps.

Se feito corretamente, seu algoritmo não deveria nem notar a mudança – corretamente aqui significa usar uma class para representar a tabela, mesmo dando a ela um método put (chave, valor) e um método get (chave) como um hashmap.

Quando a tabela intermediária estiver completa, gere a (s) instrução (ões) sql necessária (s) a partir dela, em vez da memory.

O coletor paralelo lançará um OutOfMemoryError se muito tempo estiver sendo gasto na garbage collection. Em particular, se mais de 98% do tempo total for gasto na garbage collection e menos de 2% do heap for recuperado, o OutOfMemoryError será lançado. Esse recurso foi projetado para impedir que os aplicativos sejam executados por um período prolongado, enquanto faz pouco ou nenhum progresso porque o heap é muito pequeno. Se necessário, esse recurso pode ser desativado adicionando a opção -XX:-UseGCOverheadLimit à linha de comando.

Se você está criando centenas de milhares de mapas hash, provavelmente está usando muito mais do que realmente precisa; a menos que você esteja trabalhando com arquivos ou charts grandes, o armazenamento de dados simples não deve estourar o limite de memory do Java.

Você deve tentar repensar seu algoritmo. Nesse caso, eu ofereceria mais ajuda sobre esse assunto, mas não posso fornecer nenhuma informação até que você forneça mais informações sobre o contexto do problema.

Se você tem java8 e pode usar o G1 Garbage Collector , execute seu aplicativo com:

  -XX:+UseG1GC -XX:+UseStringDeduplication 

Isso diz ao G1 para encontrar Strings similares e manter apenas um deles na memory, e os outros são apenas um ponteiro para aquele String na memory.

Isso é útil quando você tem muitas cadeias repetidas. Essa solução pode ou não funcionar e depende de cada aplicativo.

Mais informações em:
https://blog.codecentric.de/en/2014/08/string-deduplication-new-feature-java-8-update-20-2/ http://java-performance.info/java-string-deduplication/

Corrija vazamentos de memory em seu aplicativo com ajuda de ferramentas de perfil como o eclipse MAT ou VisualVM

Com o JDK 1.7.x ou versões posteriores, use G1GC , que gasta 10% na garbage collection, ao contrário de 2% em outros algoritmos de GC.

Além de configurar a memory heap com -Xms1g -Xmx2g , tente `

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

Dê uma olhada no artigo oracle para ajustar esses parâmetros.

Alguma pergunta relacionada ao G1GC em SE:

Coleta de lixo e documentação do Java 7 (JDK 7) no G1

Coleta de lixo Java G1 em produção

Estratégia Agressiva de Coletor de Lixo

Em caso de erro:

“Erro interno do compilador: java.lang.OutOfMemoryError: limite de sobrecarga do GC excedido em java.lang.AbstractStringBuilder”

Aumente o espaço do heap Java para 2 GB, ou seja, -Xmx2g.

Você precisa aumentar o tamanho da memory no Jdeveloper, vá para 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 

Para isso, use o código abaixo no arquivo Gradle do aplicativo, no encerramento do Android.

dexOptions {javaMaxHeapSize “4g”}

Para o meu caso, aumentar a memory usando a opção -Xmx foi a solução.

Eu tinha um arquivo de 10g lido em java e cada vez recebi o mesmo erro. Isso aconteceu quando o valor na coluna RES no comando top alcançou o valor definido na opção -Xmx. Então, aumentando a memory usando a opção -Xmx tudo correu bem.

Houve outro ponto também. Quando eu configurei JAVA_OPTS ou CATALINA_OPTS na minha conta de usuário e aumentei a quantidade de memory novamente, recebi o mesmo erro. Em seguida, imprimi o valor dessas variables ​​de ambiente no meu código, o que me deu valores diferentes dos que defini. A razão era que o Tomcat era a raiz para esse processo e, como eu não era um usuário, pedi ao administrador para aumentar a memory no catalina.sh no Tomcat.

Isso me ajudou a me livrar desse erro. Essa opção desativa -XX: + DisableExplicitGC

    Intereting Posts