java.lang.OutOfMemoryError: espaço de heap Java

96

Estou recebendo o seguinte erro na execução de um programa multi-threading

java.lang.OutOfMemoryError: Java heap space

O erro acima ocorreu em um dos tópicos.

  1. Até onde sei, o espaço Heap é ocupado apenas por variáveis ​​de instância. Se isso estiver correto, então por que esse erro ocorreu após funcionar bem por algum tempo, já que o espaço para variáveis ​​de instância são alocados no momento da criação do objeto.

  2. Existe alguma maneira de aumentar o espaço de heap?

  3. Que alterações devo fazer em meu programa para que ocupe menos espaço de heap?

Yatendra Goel
fonte

Respostas:

104

Se você deseja aumentar seu espaço de heap, você pode usar java -Xms<initial heap size> -Xmx<maximum heap size>na linha de comando. Por padrão, os valores são baseados na versão JRE e na configuração do sistema. Você pode descobrir mais sobre as opções de VM no site do Java .

No entanto, eu recomendaria criar o perfil de seu aplicativo para descobrir por que o tamanho do heap está sendo consumido. O NetBeans tem um profiler muito bom incluído com ele. Eu acredito que usa o jvisualvmsob o capô. Com um criador de perfil, você pode tentar descobrir onde muitos objetos estão sendo criados, quando os objetos são coletados pelo lixo e muito mais.

Thomas Owens
fonte
1
Estou usando o Netbeans, mas não sei como usar o profiler. Gostaria de saber mais sobre o criador de perfil para que possa usá-lo para localizar vazamentos de memória em meu aplicativo.
Yatendra Goel
Eu adicionei um link para uma página no site do NetBeans ( profiler.netbeans.org ) que tem uma documentação muito boa sobre o perfil, desde o básico até o uso mais avançado.
Thomas Owens
Os valores padrão mudam com as versões java, seria bom incluir essa informação em sua resposta.
Dariusz
Acabei de consertar um problema semelhante e tentei primeiro: java -jar division.jar -Xmx512m -Xms512m - isso me dá o mesmo erro, mas quando eu faço assim: java -Xmx512m -Xms512m -jar division.jar - está tudo bem. Portanto, a ordem dos parâmetros também é importante.
hipokito de
@hipokito Argumentos após o arquivo jar são passados ​​para o método main () do arquivo jar como args []
Asu
29

1.- Sim, mas se refere basicamente a toda a memória utilizada pelo seu programa.

2.- Sim veja as opções Java VM

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size

Ie

java -Xmx2g atribua 2 gigabytes de RAM no máximo para seu aplicativo

Mas primeiro você deve verificar se não há vazamento de memória.

3.- Depende do programa. Tente detectar vazamentos de memória. Esta pergunta seria muito difícil de responder. Ultimamente, você pode criar perfis usando JConsole para tentar descobrir para onde sua memória está indo

OscarRyz
fonte
enquanto que (verdadeiro);)
Gal Bracha
8

Você pode querer dar uma olhada neste site para aprender mais sobre memória na JVM: http://developer.streamezzo.com/content/learn/articles/optimization-heap-memory-usage

Achei útil usar o visualgc para observar como as diferentes partes do modelo de memória estão sendo preenchidas, para determinar o que mudar.

É difícil determinar qual parte da memória foi preenchida, portanto visualgc, pois você pode querer apenas alterar a parte que está com problema, em vez de apenas dizer:

Bem! Vou dar 1G de RAM para a JVM.

Tente ser mais preciso sobre o que está fazendo; com o tempo, provavelmente encontrará o programa melhor para isso.

Para determinar onde pode estar o vazamento de memória, você pode usar testes de unidade para isso, testando qual era a memória antes do teste e depois, e se houver uma mudança muito grande, você pode querer examiná-la, mas, você precisa faça a verificação enquanto o teste ainda está em execução.

James Black
fonte
6

Para aumentar o tamanho do heap, você pode usar o argumento -Xmx ao iniciar o Java; por exemplo

-Xmx256M
Adamski
fonte
6

Você pode obter o tamanho da memória heap por meio do programa abaixo.

public class GetHeapSize {
    public static void main(String[] args) {
        long heapsize = Runtime.getRuntime().totalMemory();
        System.out.println("heapsize is :: " + heapsize);
    }
} 

então você também pode aumentar o tamanho do heap usando: java -Xmx2g http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

user2663609
fonte
6
  1. Até onde sei, o espaço Heap é ocupado apenas por variáveis ​​de instância. Se isso estiver correto, então por que esse erro ocorreu após funcionar bem por algum tempo, já que o espaço para variáveis ​​de instância são alocados no momento da criação do objeto.

Isso significa que você está criando mais objetos em seu aplicativo ao longo de um período de tempo continuamente. Novos objetos serão armazenados na memória heap e essa é a razão para o crescimento da memória heap.

Heap não contém apenas variáveis ​​de instância. Ele armazenará todos os tipos de dados não primitivos (Objetos). A vida útil desses objetos pode ser curta (bloco de método) ou longa (até que o objeto seja referenciado em seu aplicativo)

  1. Existe alguma maneira de aumentar o espaço de heap?

Sim. Dê uma olhada neste artigo do oracle para mais detalhes.

Existem dois parâmetros para definir o tamanho do heap:

-Xms:, que define o tamanho de heap inicial e mínimo

-Xmx:, que define o tamanho máximo de heap

  1. Que alterações devo fazer em meu programa para que ocupe menos espaço de heap?

Depende da sua aplicação.

  1. Defina a memória heap máxima de acordo com os requisitos do seu aplicativo

  2. Não cause vazamentos de memória em seu aplicativo

  3. Se você encontrar vazamentos de memória em seu aplicativo, encontre a causa raiz com a ajuda de ferramentas de perfil como MAT , Visual VM , jconsole etc. Depois de encontrar a causa raiz, corrija os vazamentos.

Notas importantes do artigo oracle

Explicação: A mensagem detalhada do espaço de heap Java indica que o objeto não pôde ser alocado no heap Java. Esse erro não significa necessariamente um vazamento de memória.

Razões possíveis:

  1. Configuração inadequada (não alocação de memória suficiente)
  2. O aplicativo está retendo involuntariamente referências a objetos e isso impede que os objetos sejam coletados como lixo
  3. Aplicativos que fazem uso excessivo de finalizadores. Se uma classe tiver um método de finalização, os objetos desse tipo não terão seu espaço recuperado no momento da coleta de lixo. Se o encadeamento do finalizador não puder acompanhar, com a fila de finalização, o heap Java pode ser preenchido e esse tipo de exceção OutOfMemoryError seria lançado .

Por outro lado, use algoritmos de coleta de lixo melhores ( CMS ou G1GC )

Dê uma olhada nesta questão para entender G1GC

Ravindra babu
fonte
5
  1. Na maioria dos casos, o código não é otimizado. Libere aqueles objetos que você acha que não serão mais necessários. Evite a criação de objetos em seu loop todas as vezes. Tente usar caches. Não sei como está o seu aplicativo. Mas na programação, uma regra de vida normal também se aplica

    Prevenção é melhor que a cura. "Não crie objetos desnecessários"

DKSRathore
fonte
3
  1. As variáveis ​​locais estão localizadas na pilha. O espaço da pilha é ocupado por objetos.

  2. Você pode usar a -Xmxopção.

  3. Basicamente, o espaço de heap é usado toda vez que você aloca um novo objeto newe é liberado algum tempo depois que o objeto não é mais referenciado. Portanto, certifique-se de não manter referências a objetos de que não precisa mais.

sepp2k
fonte
1

Não, acho que você está pensando em espaço de pilha. O espaço da pilha é ocupado por objetos. A maneira de aumentá-lo é -Xmx256m, substituindo o 256 pela quantidade necessária na linha de comando.

Yishai
fonte
1

Para evitar essa exceção, se você estiver usando JUnit e Spring, tente adicioná-lo em cada classe de teste:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
Aliuk
fonte
0

No netbeans, vá para a barra de ferramentas 'Executar', -> 'Definir configuração do projeto' -> 'Personalizar' -> 'executar' da janela pop-up -> 'Opção VM' -> preencher '-Xms2048m -Xmx2048m '. Isso poderia resolver o problema do tamanho do heap.

Xiaogang
fonte