Deboguer les Applications Non Responsives
Autres langues : English Español Deutsch 日本語 한국어 Português 中文
Il existe de nombreux tutoriels de debogueur qui vous apprennent a definir des points d’arret de ligne, a enregistrer des valeurs ou a evaluer des expressions. Bien que ces connaissances seules vous donnent de nombreux outils pour deboguer votre application, les scenarios du monde reel peuvent etre un peu plus complexes et necessiter une approche plus avancee.
Dans cet article, nous apprendrons comment localiser le code qui provoque un blocage de l’interface utilisateur sans grande connaissance prealable du projet et corriger le code defectueux a la volee.
Le probleme
Si vous souhaitez suivre, commencez par cloner ce depot : https://github.com/flounder4130/debugger-example
Supposons que vous ayez une application complexe qui se bloque lorsque vous effectuez une certaine action. Vous savez comment reproduire le bug, mais la difficulte est que vous ne savez pas quelle partie du code est responsable de cette fonctionnalite.
Dans notre application exemple, le blocage se produit lorsque vous cliquez sur Button N. Cependant, il n’est pas si facile de trouver le code responsable de cette action :
Voyons comment nous pouvons utiliser le debogueur pour le trouver.
Points d’arret de methode
L’avantage des points d’arret de methode par rapport aux points d’arret de ligne est qu’ils peuvent etre utilises sur des hierarchies entieres de classes. En quoi est-ce utile dans notre cas ?
Si vous regardez le projet exemple, vous verrez que toutes les classes d’action derivent de l’interface
Action avec une
seule methode : perform() .
Definir un point d’arret de methode dans cette methode d’interface suspendra l’application chaque fois qu’une des methodes derivees est appelee. Pour definir un point d’arret de methode, cliquez sur la ligne qui declare la methode.
Demarrez la session de debogage et cliquez sur Button N. L’application est suspendue dans ActionImpl14 .
Nous savons maintenant ou se trouve le code correspondant a ce bouton.
Bien que dans cet article nous nous concentrions sur la recherche du bug, cette technique peut egalement vous faire gagner beaucoup de temps lorsque vous voulez comprendre comment quelque chose fonctionne dans une grande base de code.
Mettre l’application en pause
L’approche avec les points d’arret de methode fonctionne bien, mais elle repose sur l’hypothese que nous connaissons quelque chose sur l’interface parente. Que faire si cette hypothese est fausse, ou si nous ne pouvons pas utiliser cette approche pour une autre raison ?
Eh bien, nous pouvons meme le faire sans points d’arret. Cliquez sur Button N, et pendant que l’application est bloquee, allez dans IntelliJ IDEA. Dans le menu principal, selectionnez Run | Debugging Actions | Pause Program.
L’application sera suspendue, nous permettant d’examiner l’etat actuel des threads dans l’onglet Threads & Variables. Cela nous donne une comprehension de ce que l’application fait a ce moment. Puisqu’elle est bloquee, nous pouvons identifier la methode qui cause le blocage et remonter jusqu’au site d’appel.
Cette approche presente certains avantages par rapport a un dump de threads plus traditionnel, que nous aborderons sous peu. Par exemple, elle vous donne des informations sur les variables sous une forme pratique et vous permet de controler l’execution ulterieure du programme.
Pour plus de conseils et astuces avec Pause Program consultez Déboguer Sans Points d Arrêt et Bricoler le Mode Dieu avec le Débogueur
Dumps de threads
Enfin, nous pouvons utiliser un dump de threads, qui n’est pas strictement une fonctionnalite du debogueur. Il est disponible que vous utilisiez ou non le debogueur.
Cliquez sur Button N. Pendant que l’application est bloquee, allez dans IntelliJ IDEA. Dans le menu principal, selectionnez Run | Debugging Actions | Get Thread Dump.
Parcourez les threads disponibles a gauche, et dans AWT-EventQueue vous verrez ce qui cause le probleme.
L’inconvenient des dumps de threads est qu’ils ne fournissent qu’un instantane de l’etat du programme au moment ou ils ont ete effectues. Vous ne pouvez pas utiliser les dumps de threads pour explorer les variables ou controler l’execution du programme.
Dans notre exemple, nous n’avons pas besoin de recourir a un dump de threads. Cependant, je voulais quand meme mentionner cette technique car elle peut etre utile dans d’autres cas, comme lorsque vous essayez de deboguer une application qui a ete lancee sans l’agent de debogage.
Comprendre le probleme
Quelle que soit la technique de debogage, nous arrivons a ActionImpl14 .
Dans cette classe, quelqu’un avait l’intention d’effectuer le travail dans un
thread separe, mais a confondu
Thread.start() avec Thread.run() ,
qui execute le code dans le meme thread que le code appelant.
L’analyseur statique d’IntelliJ IDEA nous avertit meme de cela au moment de la conception :
Une methode qui effectue un travail lourd (ou dort longtemps dans ce cas) est appelee sur le thread de l’interface utilisateur et le bloque jusqu’a ce que la methode se termine. C’est pourquoi nous ne pouvons rien faire dans l’interface utilisateur pendant un certain temps apres avoir clique sur Button N.
HotSwap
Maintenant que nous avons decouvert la cause du bug, corrigeons le probleme.
Nous pourrions arreter le programme, recompiler le code, puis le relancer. Cependant, il n’est pas toujours pratique de redeployer toute l’application juste pour un petit changement.
Faisons-le intelligemment. D’abord, corrigez le code en utilisant la correction rapide suggeree :
Une fois le code pret, cliquez sur Run | Debugging Actions | Reload Changed Classes. Une bulle apparait, confirmant que le nouveau code a ete charge dans la VM.
Retournons a l’application et verifions. Cliquer sur Button N ne bloque plus l’application.
Gardez a l’esprit que HotSwap a ses limitations. Si vous etes interesse par des capacites HotSwap etendues, il pourrait etre judicieux de jeter un oeil a des outils avances comme DCEVM ou JRebel
Resume
En utilisant notre raisonnement et quelques fonctionnalites du debogueur, nous avons pu localiser le code qui causait un blocage de l’interface utilisateur dans notre projet. Ensuite, nous avons procede a la correction du code sans perdre de temps en recompilation et redeploiement, ce qui peut etre long dans les projets du monde reel.
J’espere que vous trouverez les techniques decrites utiles. Dites-moi ce que vous en pensez !
Restez a l’ecoute pour plus !