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

805

Recebo esta mensagem de erro ao executar meus testes JUnit:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Sei o que OutOfMemoryErroré, mas o que significa o limite de sobrecarga do GC? Como posso resolver isso?

Mnementh
fonte
16
Isso parece muito interessante. Eu adoraria se alguém pudesse postar algum código que gera isso.
Buhb
1
Simplesmente encontrei o problema, que levou ao uso excessivo de memória, próximo ao limite da pilha. Uma solução simples poderia ser simplesmente fornecer um pouco mais de memória Heap ao Java-Engine (-Xmx), mas isso só ajuda, se o aplicativo precisar exatamente de tanta memória, quanto o limite de heap anterior foi definido.
Mnementh 23/10/09
1
@Mnementh eu tinha dado uma resposta aqui verificar se ele ajuda stackoverflow.com/questions/11091516/...
lulu
16
@SimonKuang Observe que existem vários OutOfMemoryErrorcenários para os quais aumentar o heap não é uma solução válida: ficar sem threads nativos e sem perm gen (que é separado do heap) são dois exemplos. Tenha cuidado ao fazer declarações excessivamente amplas sobre OutOfMemoryErrors; há um conjunto inesperadamente diversificado de coisas que podem causar isso.
Tim
3
Como você resolveu o problema?
precisa

Respostas:

764

Esta mensagem significa que, por algum motivo, o coletor de lixo está demorando muito tempo (por padrão, 98% de todo o tempo de CPU do processo) e recupera muito pouca memória em cada execução (por padrão, 2% do heap).

Isso significa efetivamente que seu programa para de fazer progresso e está ocupado executando apenas a coleta de lixo o tempo todo.

Para impedir que seu aplicativo absorva o tempo da CPU sem fazer nada, a JVM lança isso Errorpara que você tenha a chance de diagnosticar o problema.

Os casos raros em que eu vi isso acontecer é que algum código criava toneladas de objetos temporários e toneladas de objetos com pouca referência em um ambiente já muito restrito à memória.

Confira o guia de ajuste do Java GC, que está disponível para várias versões do Java e contém seções sobre esse problema específico:

Joachim Sauer
fonte
9
Seria correto resumir sua resposta da seguinte maneira: "É como um erro 'Espaço fora do heap Java'. Dê mais memória com -Xmx." ?
Tim Cooper
58
@ Tim: Não, isso não seria correto. Embora fornecer mais memória possa reduzir o problema, você também deve examinar seu código e ver por que ele produz essa quantidade de lixo e por que seu código fica logo abaixo da marca "falta de memória". Geralmente é um sinal de código quebrado.
Joachim Sauer
8
Obrigado, parece que a Oracle não é realmente tão boa na migração de dados, eles quebraram o link.
Joachim Sauer
151
Você teve-me em "Graças, parece Oracle não é realmente tão bom"
Rob Grant
3
@ Guus: se vários aplicativos forem executados na mesma JVM, sim, eles podem facilmente influenciar um ao outro. Será difícil dizer qual deles está se comportando mal. Separar os aplicativos em JVMs distintas pode ser a solução mais fácil.
Joachim Sauer
215

Citando o artigo da Oracle "Ajuste da coleta de lixo da máquina virtual Java SE 6 HotSpot [tm]" :

Tempo excessivo do GC e OutOfMemoryError

O coletor paralelo lançará um OutOfMemoryError se gastar muito tempo na coleta de lixo: se mais de 98% do tempo total for gasto na coleta de lixo e menos de 2% do heap for recuperado, um OutOfMemoryError será lançado. Esse recurso foi projetado para impedir que os aplicativos sejam executados por um longo período de tempo 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.

EDIT: parece que alguém pode digitar mais rápido do que eu :)

Dave
fonte
87
"Você pode desativar isso ...", mas o OP provavelmente não deve fazer isso.
Stephen C
2
Você pode me dizer a diferença entre "-XX" e "-Xmx"? Consegui desligá-lo usando a opção "-Xmx" também.
Susheel Javadi
19
Respondendo a um comentário muito antigo aqui, mas ... @Bart O -XX:início de várias opções de linha de comando é um sinalizador que indica que essa opção é altamente específica da VM e instável (sujeita a alterações sem aviso prévio em versões futuras). De qualquer forma, o -XX:-UseGCOverheadLimitsinalizador informa à VM para desativar a verificação de limite de sobrecarga do GC (na verdade "desativa"), enquanto o seu -Xmxcomando apenas aumentou o heap. No último caso, a verificação de sobrecarga do GC ainda estava em execução , apenas parece que um monte maior resolveu os problemas de falha do GC no seu caso (isso nem sempre ajuda).
Andrzej Doyle
1
Na minha aplicação (lendo um arquivo grande do Excel no Talend), isso não funcionou e, de outros usuários, eu entendo o porquê. Isso apenas desativa o erro, mas o problema persiste e seu aplicativo passa a maior parte do tempo lidando com o GC. Nosso servidor tinha bastante RAM, então usei as sugestões do Vitalii para aumentar o tamanho da pilha.
RobbZ
Eventualmente, você receberá esse erro se seu aplicativo consumir muitos dados, limpar a memória e evitar o vazamento de dados é a melhor saída - mas requer algum tempo.
Pievis
89

Se você tem certeza de que não há vazamentos de memória no seu programa, tente:

  1. Aumente o tamanho da pilha, por exemplo -Xmx1g.
  2. Ative o coletor simultâneo de baixa pausa -XX:+UseConcMarkSweepGC.
  3. Reutilize objetos existentes, quando possível, para economizar memória.

Se necessário, a verificação do limite pode ser desativada adicionando a opção -XX:-UseGCOverheadLimità linha de comandos.

Vitalii Fedorenko
fonte
9
Não concordo com o terceiro conselho. Reutilizar objetos existentes não economiza memória (não vazar objetos antigos, economizar memória :-) Além disso, "reutilizar objeto existente" era uma prática para aliviar a pressão do GC. Mas não é sempre uma boa idéia: com GC moderna, devemos evitar situações em que objetos antigos titulares novos porque ele pode quebrar alguns pressupostos localidade ...
mcoolive
@mcoolive: Para um exemplo um tanto artificial, consulte os comentários para responder a stackoverflow.com/a/5640498/4178262 abaixo; criar o Listobjeto dentro do loop fez com que o GC fosse chamado 39 vezes em vez de 22 vezes.
Mark Stewart
45

Geralmente é o código. Aqui está um exemplo simples:

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");
    }
}

Usando o Java 1.6.0_24-b07 em um Windows 7 de 32 bits.

java -Xloggc:gc.log GarbageCollector

Então olha gc.log

  • Disparado 444 vezes usando o método BAD
  • Disparado 666 vezes usando o método WORSE
  • Disparado 354 vezes usando o método BETTER

Agora concedido, esse não é o melhor teste ou o melhor design, mas, quando se depara com uma situação em que você não tem escolha a não ser implementar um loop ou ao lidar com código existente que se comporta mal, optar por reutilizar objetos em vez de criar novos pode reduzir o número de vezes que o coletor de lixo atrapalha ...

Mike
fonte
12
Esclareça: quando você diz "Disparado n vezes", isso significa que um GC regular ocorreu n vezes ou que o erro "Limite de sobrecarga do GC excedeu" relatado pelo OP aconteceu n vezes?
Jon Schneider
Eu testei agora usando java 1.8.0_91 e nunca recebi um erro / exceção, e o "Triggered n times" era da contagem do número de linhas no gc.logarquivo. Meus testes mostram muito menos vezes no geral, mas o menor número de "Disparadores" é MELHOR e, agora, o MAU é "mais ruim" do que o pior agora. Minhas contagens: MAU: 26, MAIOR: 22, MAIOR. #: #
Mark Stewart
Eu apenas acrescentado uma modificação "WORST_YET" onde defino o List<Double> listna espira externa , em vez de antes da espira externa, e accionado 39 colecções de lixo.
Mark Stewart
36

Causa do erro de acordo com o Guia de solução de problemas da plataforma Java [8], Standard Edition : (ênfase e quebras de linha adicionadas)

[...] "Limite de sobrecarga da GC excedido" indica que o coletor de lixo está em execução o tempo todo e o programa Java está progredindo muito lentamente.

Após uma coleta de lixo, se o processo Java estiver gastando mais de aproximadamente 98% de seu tempo realizando a coleta de lixo e se estiver recuperando menos de 2% do heap e estiver realizando até agora os últimos 5 (consecutivos em tempo de compilação) lixo consecutivo coleções, então a java.lang.OutOfMemoryErroré lançada. [...]

  1. Aumente o tamanho do heap se o heap atual não for suficiente.
  2. Se você ainda receber esse erro após aumentar a memória heap, use ferramentas de perfil de memória , como MAT (ferramenta analisadora de memória), Visual VM etc. e corrija vazamentos de memória.
  3. Atualize a versão do JDK para a versão mais recente (1.8.x) ou pelo menos 1.7.xe use o algoritmo G1GC. . A meta de taxa de transferência para o GC G1 é 90% de tempo de aplicação e 10% de tempo de coleta de lixo
  4. Além de definir a memória heap com - Xms1g -Xmx2g, tente

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

Dê uma olhada em algumas perguntas relacionadas ao G1GC

Ravindra babu
fonte
29

Apenas aumente um pouco o tamanho da pilha configurando esta opção em

Executar → Executar Configurações → Argumentos → Argumentos da VM

-Xms1024M -Xmx2048M

Xms - para limite mínimo

Xmx - para limite máximo

costeletas
fonte
2
Os aplicativos Android não têm argumentsguia ... o que devemos fazer para conseguir isso?
Blaze Tama
3
Para que ferramenta é essa resposta? Essa não era uma pergunta do Eclipse.
Michael Piefel
3
Não há "limite mínimo". -Xms é o tamanho inicial.
Diego Queiroz
1
Qual é o limite máximo máximo que pode ser definido?
JPerk
14

Para mim, as seguintes etapas funcionaram:

  1. Abra o eclipse.iniarquivo
  2. mudança

    -Xms40m
    -Xmx512m

    para

    -Xms512m
    -Xmx1024m
  3. Reinicie o Eclipse

Veja aqui

Sunil Kumar Sahoo
fonte
a maneira mais simples de corrigir esse problema. Obrigado :)
Hamza
1
arquivo eclipse.ini no jdev?
Abhinaba Basu
problemas não resolvidos, mesmo quando a configuração foi alterada para isso.
Zionpi
1
O OP não fez uma pergunta do Eclipse.
Michael Piefel
1
Esta "resposta" não responde à pergunta acima.
Freitags
13

tente isso

abra o build.gradlearquivo

  android {
        dexOptions {
           javaMaxHeapSize = "4g"
        }
   }
alicanozkara
fonte
Funciona muito bem para o simulador. Alguma idéia de como isso afeta dispositivos reais? ou seja, é uma boa ideia ou está apenas ocultando o problema? Obrigado.
Joshua Pinter
11

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

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
fonte
Sim, ao usar Gradle :)
Alex
4
Como você pode pensar que essa é uma solução para a pergunta dele em geral ? Você define o tamanho do heap como 4G, o que é totalmente arbitrário em uma configuração gradle para o Android facepalm .
Julian L.
7

aumente javaMaxHeapsize no seu arquivo build.gradle (Module: app)

dexOptions {
    javaMaxHeapSize "1g"
}

para (Adicione esta linha em gradle)

 dexOptions {
        javaMaxHeapSize "4g"
    }
Sai Gopi N
fonte
3

Descrições de tamanho de heap Java (xms, xmx, xmn)

-Xms size in bytes

Example : java -Xms32m

Define o tamanho inicial do heap Java. O tamanho padrão é 2097152 (2 MB). Os valores devem ser múltiplos e maiores que 1024 bytes (1 KB). (O sinalizador -server aumenta o tamanho padrão para 32M.)

-Xmn size in bytes

Example : java -Xmx2m

Define o tamanho inicial do heap Java para a geração Eden. O valor padrão é 640K. (O sinalizador -server aumenta o tamanho padrão para 2M.)

-Xmx size in bytes

Example : java -Xmx2048m

Define o tamanho máximo para o qual o heap Java pode crescer. O tamanho padrão é 64M. (O sinalizador -server aumenta o tamanho padrão para 128M.) O limite máximo de heap é de cerca de 2 GB (2048MB).

Formatação de argumentos de memória Java (xms, xmx, xmn)

Ao definir o tamanho do heap Java, especifique seu argumento de memória usando uma das letras "m" ou "M" para MB ou "g" ou "G" para GB. Sua configuração não funcionará se você especificar "MB" ou "GB". Argumentos válidos têm esta aparência:

-Xms64m ou -Xms64M -Xmx1g ou -Xmx1G Também pode usar 2048MB para especificar 2GB Além disso, certifique-se de usar apenas números inteiros ao especificar seus argumentos. Usar -Xmx512m é uma opção válida, mas -Xmx0.5g causará um erro.

Esta referência pode ser útil para alguém.

Fénix
fonte
2

Você também pode aumentar a alocação de memória e o tamanho da pilha adicionando isso ao seu gradle.propertiesarquivo:

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

Não precisa ser 2048M e 32g, faça o tamanho que você quiser.

John Doe
fonte
2

Resolvido:
Basta adicionar
org.gradle.jvmargs=-Xmx1024m
em
gradle.properties
e se ele não existir, criá-la.

reza_khalafi
fonte
0

Estou trabalhando no Android Studio e encontrei esse erro ao tentar gerar um APK assinado para lançamento. Consegui criar e testar um APK de depuração sem problemas, mas assim que quisesse criar um APK de lançamento, o processo de compilação seria executado por minutos a fio e, finalmente, terminaria com o "Erro java.lang.OutOfMemoryError: GC limite superior excedido ". Aumentei os tamanhos de heap para o VM e o compilador Android DEX, mas o problema persistiu. Finalmente, depois de muitas horas e canecas de café, constatou-se que o problema estava no arquivo 'build.gradle' no nível do aplicativo - eu tinha o parâmetro 'minifyEnabled' para o tipo de compilação do release definido como 'false', consequentemente executando os itens Proguard no código que não passou pelo processo de redução de código '(consulte https://developer.android.) Alterei o parâmetro 'minifyEnabled' para 'true' e a compilação do release foi executada como um sonho :)

Em resumo, tive que alterar meu arquivo 'build.gradle' no nível do aplicativo de: // ...

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
    }
}

//...

para

    //...

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
    }
}

//...
Alex Ivan Howard
fonte
0

Para aumentar o tamanho da pilha no IntelliJ IDEA, siga as seguintes instruções. Funcionou para mim.

Para usuários do Windows,

Vá para o local em que o IDE está instalado e procure o seguinte.

idea64.exe.vmoptions

Edite o arquivo e adicione o seguinte.

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

É isso !!

Dulith De Costa
fonte
0

você pode tentar fazer alterações na configuração do servidor consultando esta imagem e aumentando o tamanho da memória para processar as alterações do processo destacadas em amarelo

você também pode fazer alterações no heap java abrindo cmd-> set _java_opts -Xmx2g
2g (2gigabytes), dependendo da complexidade do seu programa

tente usar variáveis ​​e variáveis ​​temporárias menos constantes

insira a descrição da imagem aqui

Rahul Jain
fonte
-1

Você precisa aumentar o tamanho da memória 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**
)

e

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**
shashi
fonte
4
Essas configurações são específicas apenas ao seu IDE local. Isso não funcionará no ambiente Prod.
Feng
-1

No Netbeans, pode ser útil criar um tamanho máximo de heap. Vá para Executar => Definir configuração do projeto => Personalizar . Na janela Executar da sua janela exibida, vá para VM Option , preencha -Xms2048m -Xmx2048m. Pode resolver o problema do tamanho da pilha.

Xiaogang
fonte
-1

A reinicialização do meu MacBook corrigiu esse problema para mim.

Thomas
fonte
-1

Não sei se isso ainda é relevante ou não, mas quero apenas compartilhar o que funcionou para mim.

Atualize a versão do kotlin para a versão mais recente disponível. https://blog.jetbrains.com/kotlin/category/releases/

e está feito.

androidStud
fonte