Layer 8Ehrlicher Tech-Support

jcmd findet keine Java-Prozesse

jcmd -l listet nichts oder nur sich selbst, obwohl die JVM läuft. Schuld ist fast immer der falsche Benutzer – und sudo macht es schlimmer, nicht besser.

Aufwand:
ca. 15 Min.
Gilt für:
JDK 21, JDK 25

Das Symptom

Ein Java-Dienst hängt, und man will einen Thread-Dump ziehen. Also jcmd -l, um die Prozess-ID zu bekommen. Die Ausgabe ist leer – oder sie enthält genau eine Zeile, nämlich den gerade laufenden jcmd-Aufruf selbst. ps zeigt den Java-Prozess dagegen völlig unbeeindruckt weiter an.

Der Reflex ist sudo jcmd -l. Das Ergebnis: immer noch nichts.

Die „Layer 8“-Wahrheit

jcmd sucht nicht in der Prozesstabelle. Es spricht die JVM über einen Anhängemechanismus an, und dessen Zugangsprüfung ist bewusst eng: Laut Oracle muss jcmd auf derselben Maschine laufen wie die JVM und dieselben effektiven Benutzer- und Gruppenkennungen haben, mit denen die JVM gestartet wurde. Nicht mehr Rechte – dieselben. Ein Prozess, der diese Prüfung nicht besteht, taucht in der Liste überhaupt nicht auf, statt eine Zugriffsverweigerung zu melden. Man sucht also einen Fehler, den es nicht gibt.

Deshalb ist sudo hier der klassische Fehlgriff. sudo macht einen zu root, und root ist eben nicht der Benutzer tomcat oder appuser, unter dem der Dienst gestartet wurde. Mehr Macht hilft nicht, wenn Übereinstimmung gefordert ist. Der Weg führt über sudo -u mit exakt der Kennung aus der ps-Ausgabe.

Und dann ist da noch die Zeile in der Dokumentation, über die man leicht hinwegliest: -l zeigt die Prozess-IDs derjenigen JVMs an, die nicht in einem separaten Docker-Prozess laufen. Wer seine Anwendung containerisiert hat und vom Wirtssystem aus diagnostiziert, bekommt also selbst mit perfekt passender Kennung eine leere Liste. Das ist kein Defekt, sondern die Namensraum-Trennung, für die man sich beim Containerisieren entschieden hat – der Diagnosebefehl muss mit hinein.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Erst die Liste ohne Argumente aufrufen

    jcmd ohne Argumente entspricht laut Dokumentation exakt jcmd -l. Bleibt die Ausgabe leer oder zeigt sie nur den jcmd-Aufruf selbst, ist das noch kein Defekt, sondern das erwartete Verhalten bei nicht passender Kennung – die eigentliche Diagnose fängt hier erst an.

    jcmd -l
    
  2. 2.

    Herausfinden, unter welchem Benutzer die JVM läuft

    Bevor man an jcmd zweifelt, klärt man die Kennung des Zielprozesses. Diese Angabe ist die einzige, die zählt: Oracle verlangt dieselben effektiven Benutzer- und Gruppenkennungen, mit denen die JVM gestartet wurde.

    ps -o user,group,pid,args -C java
    
  3. 3.

    jcmd als genau dieser Benutzer starten

    Nicht als root, sondern als der Dienstbenutzer. sudo -u wechselt die Kennung, statt sie nur zu erhöhen. Genau darauf kommt es an – der Anhängemechanismus prüft Gleichheit, nicht Privilegien.

    sudo -u tomcat jcmd -l
    
  4. 4.

    Im Container den Aufruf nach innen verlegen

    Läuft die Anwendung in Docker, hilft die richtige Kennung auf dem Wirt nicht: Die Dokumentation nimmt Prozesse in einem separaten Docker-Prozess ausdrücklich von der Auflistung aus. Der Aufruf muss in den Namensraum des Containers hinein.

    docker exec -u tomcat mein-container jcmd -l
    
  5. 5.

    Erst dann die eigentliche Diagnose fahren

    Steht die Prozess-ID, liefert jcmd die üblichen Auskünfte: Thread.print druckt alle Threads mit Aufrufstapeln, VM.flags zeigt die tatsächlich wirksamen VM-Optionen samt Werten, VM.info fasst Umgebung und Zustand der JVM zusammen. VM.flags ist dabei oft die ehrlichste Quelle – sie zeigt, was die JVM wirklich verwendet, nicht was im Startskript steht.

    jcmd 4711 Thread.print
    jcmd 4711 VM.flags
    

Häufige Fragen (FAQ)

?Der Java-Prozess läuft nachweislich, aber jcmd -l zeigt ihn nicht. Wieso?

Weil jcmd laut Oracle dieselben effektiven Benutzer- und Gruppenkennungen braucht, mit denen die JVM gestartet wurde. Läuft der Dienst als Benutzer tomcat und man ruft jcmd als eigener Benutzer auf, existiert dieser Prozess für jcmd schlicht nicht. Es gibt dafür keine Fehlermeldung, nur eine leere Liste.

?Warum hilft sudo jcmd -l nicht?

Weil sudo standardmäßig zu root wechselt und root eben nicht die Kennung ist, mit der die JVM gestartet wurde. Gefordert ist Gleichheit, nicht mehr Rechte. Der richtige Weg führt über sudo -u mit genau dem Dienstbenutzer.

?Der Prozess läuft in einem Container. Reicht dann der richtige Benutzer?

Nein. Die Dokumentation schränkt -l ausdrücklich auf Prozesse ein, die nicht in einem separaten Docker-Prozess laufen. Aus dem Wirtssystem heraus bleibt die Liste also auch dann leer, wenn die Kennungen passen. Man muss jcmd innerhalb des Containers ausführen.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWSystemzerstörendjava.lang.OutOfMemoryError: Java heap space

OutOfMemoryError: Java heap space

Der Java-Prozess läuft gegen sein Speicherlimit. Mehr Heap zu geben ist oft nur ein Pflaster – meist steckt ein Speicherleck dahinter.

SWSystemzerstörendjava.lang.OutOfMemoryError: Metaspace

java.lang.OutOfMemoryError: Metaspace

Der Heap ist halb leer, die JVM stirbt trotzdem. Metaspace liegt im nativen Speicher und hat eine eigene Grenze – ein größerer Heap hilft nicht.

SWLästigUnsupportedClassVersionError

Java: UnsupportedClassVersionError

Das Programm wurde mit einem neueren Java kompiliert, als es ausführt? Diese Meldung nennt sogar die Versionsnummern — man muss sie nur übersetzen.