Comment obtenir un thread et un tas de dump d'un processus Java sur Windows qui ne tourne pas dans une console

j'ai une application Java que j'ai exécuté à partir d'une console qui exécute un autre processus Java. Je veux obtenir un fil/tas dump de ce processus enfant.

sur Unix, je pouvais faire un kill -3 <pid> mais sur Windows AFAIK la seule façon d'obtenir un dump thread est Ctrl-Break dans la console. Mais ça ne me donne que le processus parent, pas l'enfant.

y a-t-il un autre moyen d'obtenir ce tas de ferraille?

206
demandé sur Kasun Siyambalapitiya 2009-01-02 21:17:31

15 réponses

vous pouvez utiliser jmap pour obtenir un dump de n'importe quel processus en cours, en supposant que vous connaissez le pid .

utilisez le Gestionnaire de tâches ou le moniteur de ressources pour obtenir le pid . Puis

jmap -dump:format=b,file=cheap.bin <pid>

pour obtenir le tas pour ce processus.

335
répondu rkaganda 2016-09-19 07:07:01

vous confondez deux Java dumps différents. kill -3 génère un dump de thread, pas un dump de tas.

Thread dump = les traces de pile pour chaque thread dans la JVM de sortie sur la sortie standard sous forme de texte.

tas dump = contenu de mémoire pour la sortie du processus JVM vers un fichier binaire.

Pour prendre un thread dump sur Windows, CTRL + PAUSE si votre JVM est le processus de premier plan est la manière la plus simple. Si vous avez un shell de type unix sur des fenêtres comme Cygwin ou MobaXterm, vous pouvez utiliser kill -3 {pid} comme vous pouvez dans Unix.

Pour prendre un thread dump dans Unix, CTRL + C si votre JVM est le processus au premier plan ou kill -3 {pid} travailler aussi longtemps que vous obtenez le droit de PID pour la JVM.

avec l'une ou l'autre plate-forme, Java est livré avec plusieurs utilitaires qui peuvent aider. Pour les dumps de fil, jstack {pid} est votre meilleur pari. http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html

juste pour finir le dump question out: tas dumps ne sont pas couramment utilisés parce qu'ils sont difficiles à interpréter. Mais, ils ont beaucoup d'informations utiles, si vous savez où et comment regarder. L'usage le plus courant est de localiser les fuites de mémoire. C'est une bonne pratique de définir le -D sur le java ligne de commande de sorte que le tas dump est généré automatiquement sur une OutOfMemoryError, -XX:+HeapDumpOnOutOfMemoryError mais, vous pouvez déclencher manuellement un tas dump, aussi. La plus courante est d'utiliser l'utilitaire java jmap .

NOTE: cet utilitaire n'est pas disponible sur toutes les plateformes. Depuis JDK 1.6, jmap est disponible sous Windows.

un exemple de ligne de commande ressemblerait à quelque chose comme

jmap -dump:file=myheap.bin {pid of the JVM}

La sortie "myheap.bin" n'est pas lisible par l'homme (pour la plupart d'entre nous), et vous aurez besoin d'un outil pour l'analyser. Ma préférence est MAT. http://www.eclipse.org/mat /

102
répondu Derek 2018-04-25 13:22:18

je pense que la meilleure façon de créer .le fichier HPROF dans le processus Linux est avec la commande jmap . Par exemple: jmap -dump:format=b,file=filename.hprof {PID}

26
répondu Roberto Flores 2013-10-14 22:49:10

en plus d'utiliser le jconsole/visualvm mentionné, vous pouvez utiliser jstack -l <vm-id> sur une autre fenêtre de ligne de commande, et capturer cette sortie.

le peut être trouvé en utilisant le Gestionnaire des tâches (c'est l'identifiant du processus sur windows et unix), ou en utilisant jps .

les deux jstack et jps sont inclus dans la version 6 et plus de Sun JDK.

17
répondu ankon 2015-07-01 09:07:33

je recommande le VisualVM Java distribué avec le JDK (jvisualvm.EXE.) Il peut se connecter dynamiquement et accéder aux threads et tas. J'ai trouvé précieuse pour certains problèmes.

16
répondu Lawrence Dol 2009-01-02 19:25:54

Essayez l'une des options ci-dessous.

  1. Pour la version 32 bits de la JVM:

    jmap -dump:format=b,file=<heap_dump_filename> <pid>
    
  2. Pour la version 64 bits de la JVM (explicitement citer):

    jmap -J-d64 -dump:format=b,file=<heap_dump_filename> <pid>
    
  3. Pour la version 64 bits de la JVM avec G1GC l'algorithme dans les paramètres de la VM (Uniquement les objets vivants tas est généré avec G1GC algorithme):

    jmap -J-d64 -dump:live,format=b,file=<heap_dump_filename> <pid>
    

Liées SE question: Java heap dump de l'erreur avec jmap commande : Prématuré EOF

Ont un oeil à des options différentes de jmap à ce article

14
répondu Ravindra babu 2017-10-03 15:01:38

si vous voulez un heapdump sur out-of-memory, vous pouvez démarrer Java avec l'option -XX:-HeapDumpOnOutOfMemoryError

C. F. JVM Options page de référence

11
répondu Daniel Winterstein 2012-01-18 15:59:12

si vous êtes sur le serveur-jre 8 et plus, vous pouvez utiliser ceci:

jcmd PID GC.heap_dump /tmp/dump
11
répondu Atul Soman 2017-10-03 15:00:04

vous pouvez lancer jconsole (inclus avec le SDK de Java 6) puis vous connecter à votre application Java. Il vous montrera chaque fil courant et sa trace de pile.

6
répondu Steve Kuo 2009-01-02 18:51:05

vous pouvez envoyer le kill -3 <pid> de Cygwin. Vous devez utiliser les options de Cygwin ps pour trouver des processus windows puis juste envoyer le signal à ce processus.

5
répondu krosenvold 2017-10-03 14:58:31

vous devez rediriger la sortie du second exécutable java vers un fichier. Ensuite, utilisez SendSignal pour envoyer" -3 " à votre deuxième processus.

4
répondu Yoni Roit 2009-01-02 18:26:26

si vous utilisez JDK 1.6 ou plus, vous pouvez utiliser la commande jmap pour faire un tas de Dump D'un processus Java, condition est que vous devriez connaître ProcessID.

si vous êtes sur Windows Machine, vous pouvez utiliser le Gestionnaire des tâches pour obtenir le PID. Pour les machines Linux, vous pouvez utiliser des types de commandes comme ps -A | grep java ou netstat -tupln | grep java ou top | grep java , cela dépend de votre application.

alors vous pouvez utiliser la commande comme jmap -dump:format=b,file=sample_heap_dump.hprof 1234 où 1234 est PID.

il existe des variétés de outil disponible pour interpréter le fichier hprof. Je recommande l'outil visualvm D'Oracle, qui est simple à utiliser.

3
répondu Badal 2016-02-05 03:56:01

j'ai écrit un petit script par lots pour Java 8 (en utilisant PsExec et jcmd ) nommé jvmdump.bat , qui se débarrasse des threads, tas, propriétés du système, et JVM args.

:: set the paths for your environment
set PsExec=C:\Apps\SysInternals\PsExec.exe
set JAVA_HOME=C:\Apps\Java\jdk1.8.0_121
set DUMP_DIR=C:\temp

@echo off

set PID=%1

if "%PID%"=="" (
    echo usage: jvmdump.bat {pid}
    exit /b
)

for /f "tokens=2,3,4 delims=/ " %%f in ('date /t') do set timestamp_d=%%h%%g%%f
for /f "tokens=1,2 delims=: " %%f in ('time /t') do set timestamp_t=%%f%%g
set timestamp=%timestamp_d%%timestamp_t%
echo datetime is: %timestamp%

echo ### Version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Command >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.command_line >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
echo ### Properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.system_properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% Thread.print -l >"%DUMP_DIR%\%PID%-%timestamp%-threads.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% GC.heap_dump "%DUMP_DIR%\%PID%-%timestamp%-heap.hprof"

echo Dumped to %DUMP_DIR%

il doit être exécuté dans la même session Windows de l'utilisateur qui a démarré la JVM, donc si vous vous connectez par le bureau distant vous pourriez avoir besoin de lancer une invite de commande dans Session 0 et l'exécuter à partir de là. par exemple

%PsExec% -s -h -d -i 0 cmd.exe

cela vous invitera (cliquez sur l'icône de la barre des tâches en bas) à View the message dans la session interactive, ce qui vous mènera à la nouvelle console dans l'autre session à partir de laquelle vous pouvez exécuter le script jvmdump.bat .

2
répondu isapir 2017-03-23 18:28:56

si vous ne pouvez pas (ou ne voulez pas) utiliser la console/terminal pour une raison quelconque, il existe une solution alternative. Vous pouvez faire imprimer L'application Java le thread dump pour vous. Le code qui collecte la trace de la pile est raisonnablement simple et peut être attaché à un bouton ou à une interface web.

private static String getThreadDump() {
    Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

    StringBuilder out = new StringBuilder();
    for (Map.Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) {
        Thread thread = entry.getKey();
        StackTraceElement[] elements = entry.getValue();
        out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
        out.append('\n');

        for (StackTraceElement element : elements) {
            out.append(element.toString()).append('\n');
        }
        out.append('\n');
    }
    return out.toString();
}

Cette méthode renvoie une chaîne qui ressemble à ceci:

main | prio=5 | RUNNABLE
java.lang.Thread.dumpThreads(Native Method)
java.lang.Thread.getAllStackTraces(Thread.java:1607)
Main.getThreadDump(Main.java:8)
Main.main(Main.java:36)

Monitor Ctrl-Break | prio=5 | RUNNABLE
java.net.PlainSocketImpl.initProto(Native Method)
java.net.PlainSocketImpl.<clinit>(PlainSocketImpl.java:45)
java.net.Socket.setImpl(Socket.java:503)
java.net.Socket.<init>(Socket.java:424)
java.net.Socket.<init>(Socket.java:211)
com.intellij.rt.execution.application.AppMainV2.run(AppMainV2.java:59)

Finalizer | prio=8 | WAITING
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

Reference Handler | prio=10 | WAITING
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:502)
java.lang.ref.Reference.tryHandlePending(Reference.java:191)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

pour ceux qui s'intéressent à une version Java 8 avec streams, le le code est encore plus compact:

private static String getThreadDump() {
    Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
    StringBuilder out = new StringBuilder();
    allStackTraces.forEach((thread, elements) -> {
        out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
        out.append('\n');

        Arrays.stream(elements).forEach(element -> out.append(element.toString()).append('\n'));
        out.append('\n');
    });
    return out.toString();
}

vous pouvez facilement tester CE code avec:

System.out.print(getThreadDump());
0
répondu HugoTeixeira 2018-08-03 02:00:25

sur un Oracle JDK, nous avons une commande appelée jmap (disponible dans le dossier bin de Java Home). l'utilisation de la commande est la suivante

jmap (option) (pid)

Exemple: jmap -dump:live,format=b,fichier=tas.bin (pid)

-1
répondu Suresh Ram 2018-02-22 12:38:07