Pergunta

Estou escrevendo um lado do cliente Balanço aplicativo (designer de fontes gráficas) em Java 5.Recentemente, estou me deparando com java.lang.OutOfMemoryError: Java heap space erro porque não estou sendo conservador no uso de memória.O usuário pode abrir um número ilimitado de arquivos, e o programa mantém os objetos abertos na memória.Depois de uma rápida pesquisa descobri Ergonomia na Java Virtual Machine 5.0 e outros dizendo que na máquina Windows o padrão da JVM é o tamanho máximo de heap como 64MB.

Dada esta situação, como devo lidar com esta restrição?

Eu poderia aumentar o tamanho máximo de heap usando linha de comando opção para java, mas isso exigiria descobrir a RAM disponível e escrever algum programa ou script de inicialização.Além disso, aumentando para alguns finito máximo não em última análise livrar-se do problema.

Eu poderia reescrever parte do meu código para persistir objetos no sistema de arquivos com frequência (usar banco de dados é a mesma coisa) para liberar memória.Poderia funcionar, mas provavelmente também dá muito trabalho.

Se você pudesse me indicar detalhes das ideias acima ou algumas alternativas como memória virtual automática, estendendo o tamanho do heap dinamicamente, isso será ótimo.

Foi útil?

Solução

Em última análise, você sempre terá um máximo finito de heap para usar, independentemente da plataforma em que estiver executando.No Windows 32 bits isso acontece 2GB (não especificamente heap, mas quantidade total de memória por processo).Acontece que Java opta por diminuir o padrão (presumivelmente para que o programador não possa criar programas que tenham alocação descontrolada de memória sem se deparar com esse problema e ter que examinar exatamente o que estão fazendo).

Considerando isso, existem várias abordagens que você pode adotar para determinar a quantidade de memória necessária ou para reduzir a quantidade de memória que está usando.Um erro comum com linguagens com coleta de lixo, como Java ou C#, é manter referências a objetos que você não mais está usando ou alocando muitos objetos quando você poderia reuso eles em vez disso.Contanto que os objetos tenham uma referência a eles, eles continuarão a usar o espaço de heap, pois o coletor de lixo não os excluirá.

Nesse caso, você pode usar um criador de perfil de memória Java para determinar quais métodos em seu programa estão alocando um grande número de objetos e então determinar se há uma maneira de garantir que eles não sejam mais referenciados ou de não alocá-los em primeiro lugar.Uma opção que usei no passado é "JMP" http://www.khelekore.org/jmp/.

Se você determinar que está alocando esses objetos por um motivo e precisar manter as referências (dependendo do que estiver fazendo, esse pode ser o caso), você só precisará aumentar o tamanho máximo do heap ao iniciar o programa.No entanto, depois de fazer o perfil de memória e entender como seus objetos estão sendo alocados, você deverá ter uma ideia melhor sobre a quantidade de memória necessária.

Em geral, se você não puder garantir que seu programa será executado em uma quantidade finita de memória (talvez dependendo do tamanho da entrada), você sempre encontrará esse problema.Somente depois de esgotar tudo isso você precisará examinar o cache de objetos no disco, etc.Neste ponto, você deve ter um bom motivo para dizer "Preciso de Xgb de memória" para alguma coisa e não pode contornar isso melhorando seus algoritmos ou padrões de alocação de memória.Geralmente, esse será o caso apenas para algoritmos que operam em grandes conjuntos de dados (como um banco de dados ou algum programa de análise científica) e então técnicas como cache e E/S mapeadas em memória tornam-se úteis.

Outras dicas

Execute Java com a opção de linha de comando -Xmx, que define o máximo tamanho da pilha.

Veja aqui para detalhes.

Você poderia especificar por projete quanto espaço de heap seu projeto deseja

A seguir é para Eclipse Hélios/Juno/Kepler:

Clique com o botão direito do mouse em

 Run As - Run Configuration - Arguments - Vm Arguments, 

então adicione isso

-Xmx2048m

Aumentar o tamanho do heap não é um “conserto”, é um “gesso”, 100% temporário.Ele irá travar novamente em outro lugar.Para evitar esses problemas, escreva código de alto desempenho.

  1. Use variáveis ​​locais sempre que possível.
  2. Certifique-se de selecionar o objeto correto (EX:Seleção entre String, StringBuffer e StringBuilder)
  3. Use um bom sistema de código para o seu programa (EX:Usando variáveis ​​estáticas versus variáveis ​​não estáticas)
  4. Outras coisas que podem funcionar no seu código.
  5. Tente mover-se com multy THREADING

Grande advertência ---- em meu escritório, descobrimos que (em algumas máquinas Windows) não podíamos alocar mais de 512 m para heap Java.Isso aconteceu devido ao produto antivírus Kaspersky instalado em algumas dessas máquinas.Depois de desinstalar esse produto AV, descobrimos que poderíamos alocar pelo menos 1,6 GB, ou seja, -Xmx1600m (m é obrigatório, caso contrário, levará a outro erro "Heap inicial muito pequeno") funciona.

Não faço ideia se isso acontece com outros produtos AV, mas presumivelmente isso está acontecendo porque o programa AV está reservando um pequeno bloco de memória em cada espaço de endereço, evitando assim uma única alocação realmente grande.

Os argumentos da VM funcionaram para mim no Eclipse.Se você estiver usando o Eclipse versão 3.4, faça o seguinte

Vá para Run --> Run Configurations --> em seguida, selecione o projeto em maven build -> em seguida, selecione a guia "JRE" -> em seguida, digite -Xmx1024m.

Alternativamente você poderia fazer Run --> Run Configurations --> select the "JRE" tab --> então entre -Xmx1024m

Isso deve aumentar o heap de memória para todas as compilações/projetos.O tamanho da memória acima é de 1 GB.Você pode otimizar da maneira que desejar.

Sim, com -Xmx você pode configurar mais memória para sua JVM.Para ter certeza de que você não vazará ou desperdiçará memória.Faça um despejo de pilha e use o Analisador de Memória Eclipse para analisar seu consumo de memória.

Gostaria de adicionar recomendações da Oracle solução de problemas artigo.

Exceção no thread thread_name: java.lang.OutOfMemoryError:Espaço de heap Java

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

Causas Possíveis:

  1. Problema de configuração simples, onde o tamanho de heap especificado é insuficiente para o aplicativo.

  2. O aplicativo está mantendo involuntariamente referências a objetos, e isso evita que os objetos sejam coletados como lixo.

  3. Uso excessivo de finalizadores.

Uma outra fonte potencial desse erro surge em aplicativos que fazem uso excessivo de finalizadores.Se uma classe tiver um método finalize, então os objetos desse tipo não terão seu espaço recuperado no momento da coleta de lixo

Depois coleta de lixo, os objetos são enfileirados para finalização, o que ocorre posteriormente. finalizadores são executados por um thread daemon que atende a fila de finalização.Se o finalizador thread não consegue acompanhar a fila de finalização, então o heap Java pode ficar cheio e esse tipo de Erro de falta de memória exceção seria lançada.

Um cenário que pode causar essa situação é quando um aplicativo cria tópicos de alta prioridade que causam o finalização fila aumente a uma taxa que é mais rápida que a taxa na qual o thread do finalizador está atendendo essa fila.

Siga as etapas abaixo:

  1. Abrir catalina.sh do tomcat/bin.

  2. Altere JAVA_OPTS para

    JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m 
    -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m 
    -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
    
  3. Reinicie seu gato

Maneira fácil de resolver OutOfMemoryError em java é aumentar o tamanho máximo de heap usando opções JVM -Xmx512M, isso resolverá imediatamente o seu OutOfMemoryError.Esta é minha solução preferida quando obtenho OutOfMemoryError no Eclipse, Maven ou ANT durante a construção do projeto porque, com base no tamanho do projeto, você pode facilmente ficar sem memória.

Aqui está um exemplo de aumento do tamanho máximo de heap da JVM. Além disso, é melhor manter a proporção -Xmx para -Xms de 1: 1 ou 1: 1,5 se você estiver configurando o tamanho do heap em seu aplicativo Java.

export JVM_ARGS="-Xms1024m -Xmx1024m"

Link de referência

Por padrão, para desenvolvimento, a JVM usa tamanho pequeno e configuração pequena para outros recursos relacionados ao desempenho.Mas para produção você pode ajustar, por ex.(Além disso, pode existir configuração específica do Application Server) -> (Se ainda não houver memória suficiente para satisfazer a solicitação e o heap já tiver atingido o tamanho máximo, ocorrerá um OutOfMemoryError)

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size
-Xss<size>        set java thread stack size

-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)

Por exemplo:Na plataforma Linux para configurações preferenciais do modo de produção.

Depois de baixar e configurar o servidor desta forma http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/

1.crie o arquivo setenv.sh na pasta /opt/tomcat/bin/

   touch /opt/tomcat/bin/setenv.sh

2.Abra e escreva estes parâmetros para definir o modo preferível.

nano  /opt/tomcat/bin/setenv.sh 

export CATALINA_OPTS="$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"

3.service tomcat restart

Observe que a JVM usa mais memória do que apenas o heap.Por exemplo, métodos Java, pilhas de encadeamentos e alças nativas são alocadas na memória separadas da pilha, bem como as estruturas de dados internas da JVM.

Eu enfrentei o mesmo problema com o tamanho do heap Java.

Eu tenho duas soluções se você estiver usando Java 5(1.5).

  1. basta instalar o jdk1.6 e ir para as preferências do Eclipse e definir o caminho jre do jav1 1.6 conforme você instalou.

  2. Verifique o argumento da sua VM e deixe-o ser o que for.Basta adicionar uma linha abaixo de todos os argumentos presentes nos argumentos da VM como -xms512m -xmx512m -xx: maxpermsize = ... m (192m).

acho que vai funcionar...

Eu li em outro lugar que você pode tentar - capturar java.lang.OutOfMemoryError e no bloco catch, você pode liberar todos os recursos que você sabe que podem usar muita memória, fechar conexões e assim por diante, então faça um System.gc() em seguida, tente novamente o que você ia fazer.

Outra maneira é esta, embora eu não saiba se funcionaria, mas atualmente estou testando se funcionará em meu aplicativo.

A ideia é fazer a coleta de lixo chamando System.gc() que é conhecido por aumentar a memória livre.Você pode continuar verificando isso após a execução de um código que consome memória.

//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);

Runtime runtime = Runtime.getRuntime();

if(runtime.freeMemory()<minRunningMemory)
 System.gc();

Se você precisar monitorar o uso de memória em tempo de execução, o java.lang.management ofertas de pacotes MBeans que pode ser usado para monitorar os pools de memória em sua VM (por exemplo, espaço eden, geração estável, etc.) e também o comportamento da coleta de lixo.

O espaço de heap livre relatado por esses MBeans irá variar muito dependendo do comportamento do GC, especialmente se seu aplicativo gerar muitos objetos que serão posteriormente editados pelo GC.Uma abordagem possível é monitorar o espaço de heap livre após cada GC completo, que você pode usar para tomar uma decisão sobre como liberar memória por meio da persistência de objetos.

Em última análise, a sua melhor aposta é limitar a retenção de memória tanto quanto possível, enquanto o desempenho permanece aceitável.Como observou um comentário anterior, a memória é sempre limitada, mas seu aplicativo deve ter uma estratégia para lidar com o esgotamento da memória.

Observe que se você precisar disso em uma situação de implantação, considere usar Java WebStart (com uma versão "ondisk", não a de rede - possível em Java 6u10 e posterior), pois permite especificar os vários argumentos para a JVM em uma cruz caminho da plataforma.

Caso contrário, você precisará de um iniciador específico do sistema operacional que defina os argumentos necessários.

Se esse problema estiver acontecendo no Wildfly 8 e JDK1.8, precisaremos especificar as configurações de MaxMetaSpace em vez das configurações de PermGen.

Por exemplo, precisamos adicionar a configuração abaixo no arquivo setenv.sh do wildfly.JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"

Para mais informações, por favor verifique Problema de pilha do Wildfly

Em relação ao netbeans, você pode definir o tamanho máximo de heap para resolver o problema.

Vá para 'Executar', então -> 'Definir configuração do projeto' -> 'Personalizar' -> 'executar' da janela exibida -> 'Opção de VM' -> preencha '-Xms2048m -Xmx2048m' .

Se você continuar alocando e mantendo referências ao objeto, preencherá qualquer quantidade de memória que tiver.

Uma opção é fechar e abrir um arquivo transparente quando eles trocam de aba (você apenas mantém um ponteiro para o arquivo, e quando o usuário muda de aba, você fecha e limpa todos os objetos ...isso tornará a mudança do arquivo mais lenta ...mas...), e talvez manter apenas 3 ou 4 arquivos na memória.

Outra coisa que você deve fazer é, quando o usuário abrir um arquivo, carregá-lo e interceptar qualquer OutOfMemoryError, então (como não é possível abrir o arquivo) fechar esse arquivo, limpar seus objetos e avisar o usuário que ele deve fechar os não utilizados arquivos.

Sua ideia de estender dinamicamente a memória virtual não resolve o problema, pois a máquina tem recursos limitados, então você deve ter cuidado e lidar com problemas de memória (ou pelo menos ter cuidado com eles).

Algumas dicas que vi sobre vazamentos de memória são:

--> Tenha em mente que se você colocar algo em uma coleção e depois esquecer, você ainda terá uma forte referência a isso, então anule a coleção, limpe-a ou faça algo com ela...caso contrário, você achará difícil encontrar um vazamento de memória.

-> Talvez usar coleções com referências fracas (weakhashmap...) possa ajudar com problemas de memória, mas você deve tenha cuidado com isso, pois você pode descobrir que o objeto que procura foi coletado.

-> Outra idéia que encontrei é desenvolver uma coleção persistente que seja armazenada em objetos de banco de dados menos usados ​​e carregados de forma transparente.Esta seria provavelmente a melhor abordagem ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top