Quem sou eu

terça-feira, 1 de dezembro de 2009

VisualVM: Analisando o funcionamento de sua aplicação Java

O desenvolvimento de aplicações em Java e a otimização é algo que requer uma atenção muito especial. Muitos por aí falam que odeiam o Java falando que é muito difícil de desenvolver, que tem problema de uso de memória e etc.
Os programadores Java que me desculpem, mas estou começando a achar que o problema não está no Java e sim na forma como se desenvolve e como se implanta o sistema. Acrescento ainda, o problema vem desde a Faculdade, onde não se fala absolutamente nada sobre otimização e análise de desempenho de aplicações.
Antes de liberar o sistema para a produção é extremamente importante fazer uma análise geral do funcionamento da aplicação, do uso de CPU, de memória e o número de threads geradas, para saber se a aplicação está alocando e desalocando os recursos corretamente, abrindo e fechando as threads, etc.

Bom, mas vamos ao que interessa. Como fazer para monitorar a sua JVM?

Para iniciar é necessário prepararmos a JVM para ser monitorada. Neste exemplo vou utilizar o servidor de aplicação Jetty rodando em um servidor Linux na pasta /opt/jetty.

Abra o arquivo jetty.sh que está dentro da pasta /opt/jetty/bin/ e adicione a seguinte variável no começo do arquivo (após os comentários):
JAVA_OPTIONS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
Explicando cada parâmetro:
-Dcom.sun.management.jmxremote: Habilita o gerenciamento remoto
-Dcom.sun.management.jmxremote.port=8086: Porta que será usada para conexão
-Dcom.sun.management.jmxremote.ssl=false: Habilitar ou não o SSL
-Dcom.sun.management.jmxremote.authenticate=false: Se haverá necessidade de autenticação para se conectar na JVM

Feito isto, basta iniciar o seu Jetty usando o script jetty.sh:
/opt/jetty/bin/jetty.sh start
O seu Jetty vai iniciar e permitirá que você se conecte remotamente na JVM para fazer o monitoramento.

Outra opção para iniciar o jetty é executar diretamente na linha de comando:
java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar /opt/jetty/start.jar
Para o monitoramento utilizaremos a excelente ferramenta da Sun chamada VisualVM. Não sei se é a melhor, mas atendeu às minhas necessidades e resolveu os meus problemas. :)

Execute o comando jvisualvm em qualquer máquina que tenha uma JVM instalada. No meu caso, uso Mac OS X Snow Leopard para o monitoramento.

Tela inicial do VisualVM

Na coluna na lateral esquerda execute os seguintes passos para adicionar o seu servidor remoto:
  1. Clica com o botão direito em Remote
  2. Clica em Add Remote Host...
  3. Coloca o IP ou nome da máquina a ser monitorada no campo e clica em OK
  4. Clica com o botão direito no Host adicionado
  5. Clica em Add JMX Connection...
  6. Preencha o campo Connection com IP:PORTA, onde a porta é a que foi adicionada no JAVA_OPTIONS do Jetty, no meu caso 8086, e depois clica em OK
Pronto, a sua JVM já vai ser monitorada. Você poderá acompanhar na aba Monitor em tempo real a utilização de CPU, Heap Size, número de classes e número de threads.


Na aba Threads, é possível monitorar os threads em tempo real.


Um recurso muito útil para descobrir problemas de má utilização de memória é fazer um dump das threads e analisar qual a thread que está ficando presa e qual classe que foi executada para causar o travamento da thread.
Para fazer um thread dump, basta clicar com o botão direito no IP do servidor monitorado e clicar em Thread Dump.
Ele vai gerar um dump de todas as threads rodando na sua JVM. Este comando pode demorar dependendo da quantidade de threads que você tem atualmente sendo executadas.



Ao clicar duas vezes no Dump, abrirá uma nova aba com todas as informações das suas threads.


Agora é só procurar por BLOCKED e aí você vai encontrar as threads que estão travadas.

Importante: nem sempre uma thread blocked significa que ela ficará travada para sempre. Pode acontecer de uma thread que esteja fazendo alguma operação com um banco de dados esteja esperando recurso disponível para executar o processo e aí ela fica blocked até o recurso ficar disponível. Neste caso, o problema pode estar no seu banco de dados que não está suportando a quantidade de transações, no seu pool de conexões ou no seu SQL que está mau feito.

Ah... lembrei de uma coisa legal. Se você está rodando o servidor de aplicação no mesmo host do VisualVM, você pode fazer dump do Heap do Java e fazer a análise no VisualVM. Se a aplicação está rodando remotamente, então para fazer o dump do heap e analisá-lo, é necessário fazer alguns passos extras. Mas não se preoculpe, no meu próximo post eu falarei sobre isso... :)

Agora é só você brincar com a ferramenta e descobrir o que é possível fazer com ela. :)

Links de relacionados:



Um comentário:

  1. Nivaldo, essa ferramenta pode ser utilizada (desvio de função) para monitorar maquina de um determinado usuário? suspeito que isto pode ter acontecido comigo.

    ResponderExcluir