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.
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.
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.
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.
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.
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.