Como detectar a causa do OutofMemoryError?

Eu tenho uma reclamação de que um aplicativo do meu servidor está falhando em alta carga.
É um aplicativo da Web em execução no Tomcat 5 .
Eu vejo o thread despeja e vejo que há um erro OutOfMemory

1TISIGINFO Evento de despejo “systhrow” (00040000) Detail
java / lang / OutOfMemoryError” “Falha ao criar o tópico: retVal -1073741830, errno 12”> recebido 1TIDATETIME Data: 2012/07/17 às 20:03:17 1TIFILENAME> Nome do arquivo do Javacore: C: \ ServerApplication \ Tomcat5 \ bin \ javacore.34545719.4646464.4172.0003.txt

A informação da pilha é a seguinte:

 Maximum Java heap size : 1500m Initial Java heap size : 256m 

Esta é a configuração para o tamanho inicial e máximo do heap (32 bit java)

Eu também vejo que há espaço livre disponível em heap

 1STHEAPFREE Bytes of Heap Space Free: 2D19F3C0 1STHEAPALLOC Bytes of Heap Space Allocated: 5DC00000 

Isso é 750 MB de espaço livre, certo?

E da análise do método thread, vejo que o número de Threads é 695 dos quais 49% é java/lang/Object.wait(Native Method) e 39% está em sun/misc/Unsafe.park(Native Method)
Também vejo este NO JAVA STACK 1% não tenho certeza do que isso significa.
Também 0 treads estão num impasse e 2% são Runnable.

Não sei como interpretar essa informação ou como proceder daqui para detectar a causa subjacente.
Alguma ajuda nisso?

De acordo com este post :

Existem duas causas possíveis de java.lang.OutOfMemoryError: Falha ao criar uma mensagem de thread:

  • Há muitos encadeamentos em execução e o sistema ficou sem resources internos para criar novos encadeamentos.
  • O sistema ficou sem memory nativa para usar no novo thread. Threads requerem uma memory nativa para estruturas internas da JVM, uma pilha Java ™ e uma pilha nativa.

Portanto, este erro pode ser completamente não relacionado à memory, apenas que muitos threads são criados …

EDITAR:

Como você tem 695 threads, você precisaria de 695 vezes o tamanho da pilha como memory. Considerando este post sobre limites de thread, suspeito que você esteja tentando criar muitos threads para o espaço de memory virtual disponível.

Você deve iniciar a JVM com o sinalizador -XX:+HeapDumpOnOutOfMemoryError . Isso produzirá um despejo de heap quando o OutOfMemoryError for gerado.

Então, como @Steve disse, você pode usar uma ferramenta como MAT para analisar o dump e ver quais objects estão alocados, e quem está mantendo referências a eles. Isso geralmente lhe dará algumas dicas sobre por que sua JVM está esgotando sua memory.

Eu sei o que você quer dizer, pode ser confuso encontrar algum lugar para começar.

Dê uma olhada no Eclipse Memory Analyzer (MAT). Ele usará o JHat para despejar um instantâneo de memory do seu programa em um arquivo, que você pode reabrir e analisar.

O navegador para este arquivo descreve todos os objects criados pelo programa muito bem, e você pode olhar em vários níveis para descobrir se algo é suspeito.


Anexando meus comentários para responder …

Quando o seu aplicativo da Web executável falha, despeje-o no MAT. MAT lhe dirá qual object está sendo criado várias vezes. Se é um object personalizado e geralmente é, é fácil encontrá-lo. Se não, você pode ver seu pai, amputá-lo e driblar a partir daí (desculpe pelo exemplo gráfico, eu não estou totalmente focado em SO no momento :).

Ah, e esqueci de mencionar, você pode executar o programa várias vezes sob várias condições e fazer um dump a cada vez. Em seguida, você pode analisar cada dump da tendência.


Mas no meu caso, o que devo usar? Eu tenho um aplicativo da web em execução no Tomcat

Desculpe, também perdi isso. Se não me engano, o MAT despeja o processo da JVM, portanto, enquanto a VM estiver em execução na sua checkbox, você poderá descarregar o processo e ver o que está acontecendo.


Outro comentário se transformou em solução parcial …

Isso está se tornando mais difícil do que realmente é. Sério, é bem fácil, depois de você executar o MAT uma ou duas vezes para pegar o jeito das coisas. Execute seu aplicativo até que a coisa falhe. Despejá-lo. Mudar alguma coisa. Correr, bater, despejar. Repetir. Em seguida, abra os despejos no MAT e compare o que parece suspeito.

A parte mais complicada quando eu estava aprendendo isso foi encontrar o ID do processo para despejar – o que ainda não é muito entorpecente.

Uma mensagem semelhante no IBM WebSphere mostra essa linha

“Falha ao criar um encadeamento: retVal”

como indicativo de um OOM nativo que significa que algum thread (do processo) está tentando solicitar uma grande parte da memory no heap.

O link IBM acima possui uma série de etapas – algumas das quais são específicas da IBM. Dar uma olhada.

De uma perspectiva de uso de memory nativa:

  • Configurações máximas do heap Java
  • Driver JDBC
  • Código JNI ou bibliotecas nativas
  • garbage collection de classs não utilizadas. Ensurethat -Xnoclassgc não está definido.
  • Configurações do Conjunto de Encadeamentos (conjuntos de encadeamentos de tamanho fixo)
  • Muitos classloaders etc, mas estes não são muito comuns.
  • Número de classs / classloaders de javacolors.

Outra coisa que você poderia olhar é o PermGenSpace – quão grande é?

Este link http://www.codingthearchitecture.com/2008/01/14/jvm_lies_the_outofmemory_myth.html sugere

Aumentar a alocação de heap na verdade agrava esse problema! Diminui o headroom do compilador, e outros componentes nativos, tem que brincar. Portanto, a solução para meu problema foi: 1.reduzir o heap alocado para a JVM. 2. remova os vazamentos de memory causados ​​por objects nativos que não estão sendo liberados em tempo hábil.

Você também configurou um valor em server.xml para maxThreads? O padrão é 200, mas seu aplicativo parece ter 695?

Consertar

Seguiu a technote IBM java.lang.OutOfMemoryError ao criar novos encadeamentos , especificamente o comando ‘ulimit’ para aumentar o valor do padrão 1024.

Sintoma

 [2/25/15 12:47:34:629 EST] 00000049 SystemErr R java.lang.OutOfMemoryError: Failed to create a thread: retVal -1073741830, errno 11 [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at java.lang.Thread.startImpl(Native Method) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at java.lang.Thread.start(Thread.java:936) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at org.eclipse.osgi.framework.internal.core.InternalSystemBundle.stop(InternalSystemBundle.java:251) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.RuntimeBundleActivator.shutdownEclipse(RuntimeBundleActivator.java:54) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.ServerCollaborator$ShutdownHook$1.run(ServerCollaborator.java:878) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at com.ibm.ws.security.auth.ContextManagerImpl.runAs(ContextManagerImpl.java:5459) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.security.auth.ContextManagerImpl.runAsSystem(ContextManagerImpl.java:5585) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.ServerCollaborator$ShutdownHook.run(ServerCollaborator.java:850) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.ServerCollaborator$StopAction.alarm(ServerCollaborator.java:809) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ejs.util.am._Alarm.run(_Alarm.java:133) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1815) 

Meio Ambiente

CentOS 6.6 64 bits IBM WAS 8.5.0.2 64 bits

Referências

  • Diretrizes para Configurar Ulimits (WebSphere Application Server)