Je devais exécuter jmap
afin de prendre le tas de données de mon processus. mais jvm
est retourné:
Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
J'ai donc utilisé le -F
:
./jmap -F -dump:format=b,file=heap.bin 10330
Attaching to process ID 10331, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.51-b03
Dumping heap to heap.bin ...
-F
vous convient-il pour prendre heap dump?jmap
vs jmap -F
, ainsi que jstack
contre jstack -F
utilisent des mécanismes complètement différents pour communiquer avec la machine virtuelle Java cible.
Lorsqu'ils sont exécutés sans -F
, ces outils utilisent Mécanisme d'attachement dynamique . Cela fonctionne comme suit.
Avant de se connecter au processus Java 1234, jmap
crée un fichier .attach_pid1234
dans le répertoire de travail du processus cible ou à /tmp
.
Ensuite, jmap
envoie SIGQUIT
au processus cible. Lorsque la machine virtuelle Java intercepte le signal et trouve .attach_pid1234
, elle démarre le thread AttachListener
.
AttachListener
thread crée le socket de domaine UNIX /tmp/.Java_pid1234
pour écouter les commandes à partir d'outils externes.
Pour des raisons de sécurité, lorsqu'une connexion (à partir de jmap
) est acceptée, JVM vérifie que les informations d'identification de l'homologue de socket sont égales à euid
et egid
du processus JVM. C'est pourquoi jmap
ne fonctionnera pas s'il est exécuté par un utilisateur différent (même par un utilisateur root).
jmap
se connecte au socket et envoie la commande dumpheap
.
Cette commande est lue et exécutée par le thread AttachListener
de la machine virtuelle Java. Toutes les sorties sont renvoyées au socket. Étant donné que le vidage de segment de mémoire est effectué directement dans le processus par la machine virtuelle Java, l'opération est très rapide. Cependant, JVM ne peut le faire qu’au niveau de safepoints . Si un point de sécurité ne peut pas être atteint (par exemple, le processus est bloqué, ne répond pas ou si un GC est long), jmap
expirera et échouera.
Résumons les avantages et les inconvénients de Dynamic Attach.
Avantages.
jmap
ou jstack
pour vous connecter à n’importe quelle version de JVM.Les inconvénients.
euid
egid
) que la machine virtuelle Java cible.-XX:+DisableAttachMechanism
.Lorsqu'ils sont exécutés avec -F
, les outils basculent vers un mode spécial doté de HotSpot Serviceability Agent . Dans ce mode, le processus cible est gelé. les outils lisent sa mémoire via des fonctions de débogage de système d'exploitation, à savoir, ptrace
sur Linux.
jmap -F
appelle PTRACE_ATTACH
sur la machine virtuelle Java cible. Le processus cible est suspendu sans condition en réponse au signal SIGSTOP
.
L'outil lit la mémoire de la machine virtuelle Java à l'aide de PTRACE_PEEKDATA
. ptrace
ne peut lire qu'un mot à la fois, il faut donc trop d'appels pour lire le gros segment du processus cible. C'est très et très lent.
L'outil reconstruit les structures internes de la machine virtuelle Java en fonction de la connaissance de la version de cette machine. Étant donné que les différentes versions de JVM ont une structure de mémoire différente, le mode -F
ne fonctionne que si jmap
provient du même JDK que le processus Java cible.
L'outil crée lui-même le vidage de segment puis reprend le processus cible.
_/ Avantages.
ptrace
fonctionne chaque fois que les privilèges de niveau système sont suffisants. Par exemple. root
peut vider les processus de tous les autres utilisateurs.Les inconvénients.
jmap
essaie de gérer tous les cas particuliers, il peut arriver que la machine virtuelle Java cible ne soit pas dans un état cohérent.Remarque
Il existe un moyen plus rapide de réaliser des vidages de tas en mode forcé. Commencez par créer un coredump avec gcore
, puis exécutez jmap
sur le fichier core généré. Voir la question connexe .
Je viens de découvrir que jmap (et vraisemblablement jvisualvm lorsqu’il l’utilise pour générer un vidage de tas) impose que l’utilisateur exécutant jmap soit le même utilisateur exécutant le processus qui tente d’être déchargé.
dans mon cas, le JVM que je veux un tas de vidage est en cours d'exécution par l'utilisateur de Linux "jboss". Alors, où Sudo jmap -dump:file.bin <pid>
signalait "Impossible d'ouvrir socket:", j'ai pu récupérer mon tas de données en utilisant:
Sudo -u jboss jmap -dump:file.bin <pid>
Si votre application s'exécute en tant que service systemd. Vous devez ouvrir le fichier de service sous /usr/lib/systemd/system/
et nommé par votre nom de service. Puis vérifiez si l'attribut privateTmp est vrai.
Si c'est vrai, vous devez le changer en false, puis actualiser le service par commande comme suit:
systemctl daemon-reload
systemctl restart [servicename]
Si vous souhaitez exécuter jmap/jcmd avant le redémarrage, vous pouvez utiliser le script execStop du fichier de service. Il suffit de mettre la commande et d'exécuter systemctl stop [service name]
Tout comme ben_wing said, vous pouvez exécuter avec:
Sudo -u jboss-as jmap -dump:file.bin <pid>
(Dans mon cas, l'utilisateur est jboss-as
, mais le vôtre peut être jboss
ou un autre.)
Mais cela ne suffisait pas, car il m'a demandé un mot de passe ([Sudo] password for ec2-user:
), bien que je puisse exécuter Sudo
sans me demander un mot de passe avec d'autres commandes.
J'ai trouvé la solution ici , et je devais simplement ajouter une autre variable Sudo
:
Sudo sudo -u jboss-as jmap -dump:file.bin <pid>
Cela fonctionne aussi avec d'autres commandes comme jcmd
et jinfo
.