Thread Dumps
A obtenção de um thread dump ajuda a determinar o que um servidor está fazendo em um dado momento. Um thread dump lista todas as threads sendo executadas por uma aplicação Java e apresenta um stack trace para cada thread. Examinar um thread dump pode dar pistas de se um servidor está parando em determinados momentos. Por exemplo, assumindo que um servidor parou por algum motivo após uma aplicação ter sido iniciada, um thread dump pode ajudar a localizar a causa da parada.
A JVM produz um thread dump quando recebe um sinal QUIT. Este sinal pode ser enviado de várias formas, mas ele é geralmente enviado por um comando que envia sinais ou por uma combinação de teclas executadas na janela da aplicação Java em execução. No Unix/Linux, a combinação <ctrl>\ ou o comando kill -QUIT id-do-processo (equivale ao kill -3 id-do-processo) podem gerar um thread dump. No Windows, utilize a combinação <ctrl><break>. Outra forma, é utilizar a interface GUI do jconsole que vem com o JDK 5.
O jconsole contém seis abas que mostram diversas informações sobre uma aplicação em execução. Uma delas é nomeada Threads e provê as mesmas informações mostradas por um thread dump.
Para executar uma aplicação Java de forma que esta possa ser monitorada pelo jconsole é necessário iniciá-la com o argumento -Dcom.sun.management.jmxremote. No caso do JBoss AS por exemplo, este argumento pode ser informado na variável de ambiente JBOSS_OPTS ou nos scripts de inicialização (run.*).
O jconsole também pode ser utilizado para substituir as funções de gerenciamento oferecidas pelo jmx-console. Você pode ler mais a respeito e ver como realizar a configuração do JBoss para suportar o gerenciamento de seus MBeans pelo jconsole, lendo esta página no wiki do JBoss.
A listagem produzida por um thread dump é longa. Desta forma, para visualizá-la é interessante iniciar o JBoss AS com o comando abaixo que irá gerar toda a saída do console padrão e de erros para o arquivo jboss.log:
$ run.sh >> jboss.log 2>&1
Monitore o arquivo jboss.log com o comando tail em um outro teminal e após perceber que o JBoss finalizou seu startup, execute a combinação de teclas <ctrl>\ na janela de execução do JBoss. Isto irá gerar um thread dump e também irá desvincular o JBoss AS do seu terminal corrente (sem entretanto, pará-lo).
Você poderá observar então o conteúdo do arquivo jboss.log que irá conter o thread dump. Ele irá conter uma lista de todas as threads que estão alocadas. Cada thread tem um nome e na maioria das vezes, este nome dá boas dicas da sua função. Você pode por exemplo adivinhar as funções das threads nomeadas “RMI TCP Accept-4444″ e “ScannerThread” não é? As threads listadas no início do thread dump são as que são utilizadas pelo JBoss e geralmente, as que estão no final são das da JVM. Segue uma lista de threads interessantes em execução no JBoss:
| Nome da Thread | Descrição |
|---|---|
| CompilerThread1 | Utilizada para a compilação de código Java, geralmente JSPs. Pode haver tantas quanto forem os processadores da máquina. Elas não estão presentes se não estiver sendo executada alguma compilação |
| GC Daemon | Utilizada para a execução do Garbage Collector. Esta thread está presente enquanto ele está sendo executado. |
| http-0.0.0.0-8080-1 | Utilizada para processar requisições HTTP de algum cliente. O endereço IP (0.0.0.0) e a porta são variáveis de acordo com a conexão socket aberta. O dígito final varia por requisição |
O stack trace abaixo da descrição da thread mostra a pilha de execução dos métodos executados pela thread no momento em que o thread dump foi gerado e é extremamente útil para se descobrir o que estava ocorredo naquele momento. Observando com calma, percebemos o que a thread estava fazendo:
Name: http-0.0.0.0-8080
State: RUNNABLE
Total blocked: 0 Total waited: 0Stack trace:
java.net.PlainSocketImpl.socketAccept(Native Method)
java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
java.net.ServerSocket.implAccept(ServerSocket.java:450)
java.net.ServerSocket.accept(ServerSocket.java:421)
org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)
org.apache.tomcat.util.net.PoolTcpEndpoint.acceptSocket(PoolTcpEndpoint.java:407)
org.apache.tomcat.util.net.PoolTcpEndpoint.run(PoolTcpEndpoint.java:647)
java.lang.Thread.run(Thread.java:595)
Outra forma de se gerar um thread dump é através do jmx-console do JBoss ou do utilitário de linha de comando twiddle. Para obter um thread dump através do utilitário twiddle em um servidor linux, o seguinte comando poderia ser executado:
$ twiddle.sh invoke jboss.system:type=ServerInfo listThreadDump
Para buscar mais informações a respeito deste assunto, sugiro que você leia: