Alexandro Félix

"Conhecimento é poder." (Francis Bacon)

Analisando Thread Dumps

leave a comment »

Análise de thread dumps, é uma tarefa delicada, é necessário bastante sensibilidade para se fazer uma análise eficiente.

Neste post tentarei passar meu conhecimento sobre este assunto, e espero que seja útil no troubleshooting de quem tiver acesso a este post.

Ao decorrer deste post, tentarei passar as diferenças entre as duas principais JVMs em uso(Hotspot Sun e Jrockit da Bea).

Uma thread…

Uma thread em stado runnable, pode ser uma thread em execução em um processador, ou uma thread pronta para ser executada quando houver algum processador disponível. Tenha em mente que somente haverá uma thread em execução por processador, todas as outras em estado de runnable, estarão esperando por sua vez.
Veja como verificar o estado das threads em diferentes jvms, como mostrado abaixo:
Sun Hotspot
Aplicações usam monitor locks, para sincronizar o acesso a sessões críticas, onde o acesso por mais de uma thread simultanemanete, pode causar um comportamento indesejado. Então quando uma thread tem waiting for monitor entry como a thread abaixo, significa que a thread está esperando para entrar em uma sessão sincronizada, onde somente uma thread é permitida por vez.
“Thread-0” daemon prio=10 tid=0x08f3fc00 nid=0xb6a waiting for monitor entry [0x8fbea000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.consensusti.thread.DinerThread.run(DinerThread.java:120)
– waiting to lock <0xb02cff00> (a java.lang.Object)
– locked <0xb02cfef8> (a java.lang.Object)
Estado da thread(Thread.state)
Esperando que o objeto 0x8fbea000 seja liberado para continuar sua execução(waiting for monitor entry)
Com essas informações você é capaz de afirma que a thread abaixo está em sleeping .
“Fred” prio=10 tid=0x8fc1a000 nid=0xbe4 waiting on condition [0x8fa2a000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.consensusti.thread.AccountDanger.makeWithdrawal(AccountDanger.java:36)
at com.consensusti.thread.AccountDanger.run(AccountDanger.java:21)
at java.lang.Thread.run(Thread.java:619)
Aplicações usam monitor locks, para sincronizar o acesso a sessões críticas, onde o acesso por mais de uma thread simultanemanete, pode causar um comportamento indesejado.
Jrockit
O mesmo pincípio de thread waiting mencionado acima, pode ser verificado na thread abaixo, onde thread está esperando por um objeto a ser liberado por outra thread, e assim continuar sua execução.
“Thread-0” id=10 idx=0x30 tid=2714 prio=5 alive, in native, blocked, daemon
— Blocked trying to get lock: java/lang/Object@0x8e2d278[fat lock]
at jrockit/vm/Threads.waitForUnblockSignal()V(Native Method)
at jrockit/vm/Locks.fatLockBlockOrSpin(Locks.java:1679)
at jrockit/vm/Locks.lockFat(Locks.java:1780)
at jrockit/vm/Locks.monitorEnterSecondStageHard(Locks.java:1312)
at jrockit/vm/Locks.monitorEnterSecondStage(Locks.java:1259)
at jrockit/vm/Locks.monitorEnter(Locks.java:2466)
at com/consensusti/thread/DinerThread.run(DinerThread.java:118)
^– Holding lock: java/lang/Object@0x8e2d270[fat lock]
at jrockit/vm/RNI.c2java(IIIII)V(Native Method)
— end of trace
Thread em execução(alive)
Executando código interno de jvm(in native)
Gerando Java Thread Dumps
Unix-like
A maneira mais prática é enviar um kill -3
ou kill -QUIT

Windows
Pressione Crtl+Break
Através de Código Java
Thread.dumpStack()
printStackTrace()
Weblogic
Weblogic oferece um botão chamado Dump Thread Stacks em Monitoring/Thread
Você também pode usar o WLST da seguinte forma:
connect(’weblogic’, ‘weblogic1’, ‘t3://127.0.0.1:7001’)
cd(’serverRuntime:/JVMRuntime/AdminServer’)
cmo.getThreadStackDump()
Dica:
Quando estiver analisando algum problema em uma aplicação, é muito importante que você gere várias thred dumps para que identificar de maneira correta seus bottlenecks e entender o estado da aplicação.
Lendo um thread dump
Ao ler um thread dump, seu principal objetivo é encontrar onde está a contenção de sua aplicação, o que está prevenindo outras threads de continuarem sua execução.
Geralmente uma aplicação com lentidão terá como característica, um alto número de threads, waiting for monitor entry, ou blocked trying to get lock on an object, dependendo da jvm. Neste caso você verifica o objeto ao qual estas threads estão tentando adquirir um “lock” e procura qual thread está segurando este lock. Esta thread será identifica por holding lock(jrockit), ou locked(sun) <0xb0230b10> dependendo da JVM.
Identificando tal thread, você pode verificar o que esta thread está executando, a partir daí iniciar um processo de troubleshooting mais direcionado.
Quando por exemplo você tiver uma thread holding lock e efetuando operações de I/O por um longo tempo, você deverá checar se há algo de errado com os discos de seu servidor, se por acaso está executando operações de rede, deverá ser verificada a conexão, e assim por diante até que se encontre o real problema.
Obs: Uma aplicação lenta, não é necessariamente lenta por culpa própria, outros fatores podem influenciar na performance, e você poderá detectar através de um thread dump.
Dead Lock
Um dead lock é formado por duas ou mais threads. Podemos ter uma Thread A com lock em um objeto e tentanto obter lock em um objeto que teve seu lock adquirido por uma Thread B e esta Thread B pode estar.
Para nossa sorte, um thread dump tanto da jvm da Sun quanto a Jrockit, nos alertam sobre a existência de um deadlock na aplicação.
Veja a seguir:
Found one Java-level deadlock:
=============================
“Thread-4”:
waiting to lock monitor 0x094554e4 (object 0xb013fef8, a java.lang.Object),
which is held by “Thread-0”
“Thread-0”:
waiting to lock monitor 0x09457a00 (object 0xb013ff00, a java.lang.Object),
which is held by “Thread-1”
“Thread-1”:
waiting to lock monitor 0x09456de4 (object 0xb013ff08, a java.lang.Object),
which is held by “Thread-2”
“Thread-2”:
waiting to lock monitor 0x09456164 (object 0xb013ff10, a java.lang.Object),
which is held by “Thread-3”
“Thread-3”:
waiting to lock monitor 0x09421080 (object 0xb013ff18, a java.lang.Object),
which is held by “Thread-4”
Para analisar thread dump de uma JVM IBM ou Sun você poderá usar o Thread Monitor Analyzer
Ferramenta bastante simples e intuitiva.
Você pode simular um dead lock através da seguinte classe:
Quando houver um deadlock, você receberá uma mensagem, e você terá então 10 minutos para tirar um thread dump, e verificar o resultado.

Teste esta classe com diferentes JVMs, e assim você poderá ver as particularidades de cada.

/**

* DinerThread.java
* Copyright (c) 2002 by Dr. Herong Yang
*/
import java.util.*;

public class DinerThread extends Thread {

public static final int numberOfThreads = 5;
public static Object[] listOfLocks = new Object[numberOfThreads];
public static char[] dinerTable = new char[4*numberOfThreads];
public static char[] lockedDiner = new char[4*numberOfThreads];
public static Random randomGenerator = new Random();
public static int unitOfTime = 100;
private int threadIndex;

public static void main(String[] a) throws InterruptedException {

for (int i=0; i
listOfLocks[i] = new Object();

for (int i=0; i

dinerTable[4*i] = '|';
dinerTable[4*i+1] = ' ';
dinerTable[4*i+2] = '-';
dinerTable[4*i+3] = ' ';
lockedDiner[4*i] = ' ';
lockedDiner[4*i+1] = '|';
lockedDiner[4*i+2] = '=';
lockedDiner[4*i+3] = ' ';
}

for (int i=0; i

Thread t = new DinerThread(i);
t.setDaemon(true);
t.start();

}

String lockedString = new String(lockedDiner);
System.out.println("The diner table:");

long step = 0;

while (true) {
step++;
System.out.println((new String(dinerTable))+"   "+step);

if (lockedString.equals(new String(dinerTable)))
break;

try {

Thread.sleep(unitOfTime);

} catch (InterruptedException e) {

System.out.println("Interrupted.");

}

}

System.out.println("The diner is locked.");
Thread.sleep(10000);

}

public DinerThread(int i) {

threadIndex = i;

}

public void run() {

while (!isInterrupted()) {

try {

sleep(unitOfTime*randomGenerator.nextInt(6));

} catch (InterruptedException e) {

break;

}

// Try to get the chopstick on the left

Object leftLock = listOfLocks[threadIndex];

synchronized (leftLock) {

int i = 4*threadIndex;

dinerTable[i] = ' ';
dinerTable[i+1] = '|';
dinerTable[i+2] = '=';
try {

sleep(unitOfTime*1);

} catch (InterruptedException e) {

break;

}

// Try to get the chopstick on the right
Object rightLock =
listOfLocks[(threadIndex+1)%numberOfThreads];

synchronized (rightLock) {

dinerTable[i+2] = 'o';
dinerTable[i+3] = '|';
dinerTable[(i+4)%(4*numberOfThreads)] = ' ';

try {

sleep(unitOfTime*1);

} catch (InterruptedException e) {

break;

}

dinerTable[i] = '|';
dinerTable[i+1] = ' ';
dinerTable[i+2] = '-';
dinerTable[i+3] = ' ';
dinerTable[(i+4)%(4*numberOfThreads)] = '|';
}

}

}

}
}

Abraço a todos, espero ter ajudado

Alexandro Félix.

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s

%d bloggers like this: