AIX® se bloque

S'il ne se produit pas d'interblocage entre les unités d'exécution, réfléchissez aux autres raisons pouvant expliquer pourquoi les unités d'exécution n'effectuent pas un travail utile.

En général, cet état se produit pour l'une des raisons suivantes :
  1. Les unités d'exécution sont à l'état "en attente", et attendent que le travail à effectuer leur soit "notifié".
  2. Les unités d'exécution se trouvent dans des cycles de veille explicites.
  3. Les unités d'exécution se trouvent dans des appels d'E-S en attente de travail.
Les deux premières raisons impliquent une erreur dans le code Java™ , soit celui de l'application, soit celui des fichiers de classe standard inclus dans le SDK.

La troisième raison, c'est-à-dire le cas où les unités d'exécution sont en attente d'E-S (par exemple sur des sockets) nécessite d'être analysé plus en détail. Le processus à l'autre extrémité de l'E-S a-t-il échoué ? Y a-t-il des problèmes réseau ?

Pour savoir comment l'outil javadump est utilisé pour diagnostiquer les boucles, voir THREADS. Si vous ne pouvez pas diagnostiquer le problème à l'aide du vidage java et si le processus semble toujours utiliser des cycles du processeur, cela signifie qu'il est entré dans une boucle sans fin ou qu'il est affecté par de très mauvaises performances. L'utilisation de ps -mp [process id] -o THREAD permet aux unités d'exécution d'un processus particulier d'être surveillées afin de déterminer quelles sont les unités d'exécution qui utilisent le temps UC. Si le processus est entré dans une boucle sans fin, il est probable qu'un petit nombre d'unités d'exécution utiliseront ce temps. Par exemple :

$ ps -mp 43824 -o THREAD
    USER   PID  PPID     TID ST  CP PRI SC    WCHAN        F     TT BND COMMAND
  wsuser 43824 51762       - A   66  60 77        *   200001  pts/4   - java ...
       -     -     -    4021 S    0  60  1 22c4d670   c00400      -   - -
       -     -     -   11343 S    0  60  1 e6002cbc  8400400      -   - -
       -     -     -   14289 S    0  60  1 22c4d670   c00400      -   - -
       -     -     -   14379 S    0  60  1 22c4d670   c00400      -   - -
...
       -     -     -   43187 S    0  60  1 701e6114   400400      -   - -
       -     -     -   43939 R   33  76  1 20039c88   c00000      -   - -
       -     -     -   50275 S    0  60  1 22c4d670   c00400      -   - -
       -     -     -   52477 S    0  60  1 e600ccbc  8400400      -   - -
...
       -     -     -   98911 S    0  60  1 7023d46c   400400      -   - -
       -     -     -   99345 R   33  76  0        -   400000      -   - -
       -     -     -   99877 S    0  60  1 22c4d670   c00400      -   - -
       -     -     -  100661 S    0  60  1 22c4d670   c00400      -   - -
       -     -     -  102599 S    0  60  1 22c4d670   c00400      -   - -
...

Les unités d'exécution comportant la valeur "R" sous "ST" sont à l'état "exécutable", et peuvent donc accumuler du temps processeur. Que font ces unités d'exécution ? La sortie de ps montre le TID (Id de l'unité d'exécution du noyau) de chaque unité d'exécution. Il peut être mappé à l'ID d'unité d'exécution Java à l'aide de dbx. La sortie de la commande thread se présente comme suit :

thread  state-k     wchan    state-u    k-tid   mode held scope function
 $t1     wait      0xe60196bc blocked   104099     k   no   sys  _pthread_ksleep
>$t2     run                  blocked    68851     k   no   sys  _pthread_ksleep
 $t3     wait      0x2015a458 running    29871     k   no   sys  pthread_mutex_lock
...
 $t50    wait                 running    86077     k   no   sys  getLinkRegister
 $t51    run                  running    43939     u   no   sys  reverseHandle     
 $t52    wait                 running    56273     k   no   sys  getLinkRegister
 $t53    wait                 running    37797     k   no   sys  getLinkRegister
 $t60    wait                 running     4021     k   no   sys  getLinkRegister
 $t61    wait                 running    18791     k   no   sys  getLinkRegister
 $t62    wait                 running    99345     k   no   sys  getLinkRegister   
 $t63    wait                 running    20995     k   no   sys  getLinkRegister

En faisant correspondre la valeur du TID de ps avec la valeur k-tid de la commande dbx thread, vous pouvez voir que les méthodes en cours d'exécution dans ce cas sont reverseHandle et getLinkRegister.

Vous pouvez maintenant utiliser dbx pour générer la pile d'unité d'exécution C de ces deux unités d'exécution avec la commande dbx thread des numéros d'unité d'exécution dbx correspondants ($tx). Pour obtenir la trace de pile complète, y compris les cadres Java, mappez le numéro d'unité d'exécution dbx à la valeur pthread_t des unités d'exécution, qui est répertoriée par le fichier de vidage Java, et qui peut être obtenue à partir de la structure ExecEnv de chaque unité d'exécution à l'aide de l'afficheur de vidage. Pour cela, utilisez la commande dbx thread info [dbx thread number], qui génère une sortie du type suivant :

thread  state-k     wchan    state-u    k-tid   mode held scope function
 $t51    run                  running    43939     u   no   sys  reverseHandle
      general:
         pthread addr = 0x220c2dc0         size         = 0x18c
         vp addr      = 0x22109f94         size         = 0x284
         thread errno = 61
         start pc     = 0xf04b4e64
         joinable     = yes
         pthread_t    = 3233
      scheduler:
         kernel       =
         user         = 1 (other)
      event :
         event        = 0x0
         cancel       = enabled, deferred, not pending
      stack storage:
         base         = 0x220c8018         size         = 0x40000
         limit        = 0x22108018
         sp           = 0x22106930

Elle montre que la valeur de TID d ps (k-tid dans dbx) correspond au numéro d'unité d'exécution dbx 51, qui a un pthread_t de 3233. En recherchant le pthread_t dans le fichier de vidage java, vous avez maintenant ne trace de pile complète :

"Worker#31" (TID:0x36288b10, sys_thread_t:0x220c2db8) Native Thread State: 
ThreadID: 00003233 Reuse: 1 USER SUSPENDED Native Stack Data : base: 22107f80 
pointer 22106390 used(7152) free(250896) 
----- Monitors held -----
java.io.OutputStreamWriter@3636a930 
com.ibm.servlet.engine.webapp.BufferedWriter@3636be78 
com.ibm.servlet.engine.webapp.WebAppRequestDispatcher@3636c270 
com.ibm.servlet.engine.srt.SRTOutputStream@36941820 
com.ibm.servlet.engine.oselistener.nativeEntry.NativeServerConnection@36d84490 JNI pinning lock 

----- Native stack ----- 

_spin_lock_global_common pthread_mutex_lock - blocked on Heap Lock 
sysMonitorEnterQuicker sysMonitorEnter unpin_object unpinObj 
jni_ReleaseScalarArrayElements jni_ReleaseByteArrayElements 
Java_com_ibm_servlet_engine_oselistener_nativeEntry_NativeServerConnection_nativeWrite 

------ Java stack ------ () prio=5 

com.ibm.servlet.engine.oselistener.nativeEntry.NativeServerConnection.write(Compiled Code) 
com.ibm.servlet.engine.srp.SRPConnection.write(Compiled Code) 
com.ibm.servlet.engine.srt.SRTOutputStream.write(Compiled Code) 
java.io.OutputStreamWriter.flushBuffer(Compiled Code) 
java.io.OutputStreamWriter.flush(Compiled Code) 
java.io.PrintWriter.flush(Compiled Code) 
com.ibm.servlet.engine.webapp.BufferedWriter.flushChars(Compiled Code) 
com.ibm.servlet.engine.webapp.BufferedWriter.write(Compiled Code) 
java.io.Writer.write(Compiled Code) 
java.io.PrintWriter.write(Compiled Code) 
java.io.PrintWriter.write(Compiled Code) 
java.io.PrintWriter.print(Compiled Code) 
java.io.PrintWriter.println(Compiled Code)
pagecompile._identifycustomer_xjsp.service(Compiled Code) 
javax.servlet.http.HttpServlet.service(Compiled Code) 
com.ibm.servlet.jsp.http.pagecompile.JSPState.service(Compiled Code) 
com.ibm.servlet.jsp.http.pagecompile.PageCompileServlet.doService(Compiled Code) 
com.ibm.servlet.jsp.http.pagecompile.PageCompileServlet.doGet(Compiled Code) 
javax.servlet.http.HttpServlet.service(Compiled Code) 
javax.servlet.http.HttpServlet.service(Compiled Code)

A l'aide de la trace de pile complète, il est possible d'identifier toute boucle sans fin. L'exemple précédent illustre l'utilisation de spin_lock_global_common, qui est une attente à l'état occupé sur un verrouillage, d'où l'utilisation de temps UC.