Comment forcer le nettoyage de la mémoire à partir du shell?


106

Donc, je regarde un tas avec jmap sur une boîte distante et je veux forcer le ramassage des ordures dessus. Comment faire cela sans entrer dans jvisualvm ou jconsole et ses amis?

Je sais que vous ne devriez pas avoir l'habitude de forcer le ramassage des ordures - vous devriez simplement comprendre pourquoi le tas est grand / grandit.

Je me rends également compte que System.GC () ne force pas réellement le garbage collection - il indique simplement au GC que vous souhaitez que cela se produise.

Cela dit, y a-t-il un moyen de le faire facilement? Une application de ligne de commande qui me manque?


Réponses:


25

Vous pouvez le faire via le programme gratuit jmxterm .

Allumez-le comme ceci:

java -jar jmxterm-1.0-alpha-4-uber.jar

De là, vous pouvez vous connecter à un hôte et déclencher GC:

$>open host:jmxport
#Connection to host:jmxport is opened
$>bean java.lang:type=Memory
#bean is set to java.lang:type=Memory
$>run gc
#calling operation gc of mbean java.lang:type=Memory
#operation returns: 
null
$>quit
#bye

Consultez la documentation sur le site Web de jmxterm pour obtenir des informations sur l'incorporation de ceci dans bash / perl / ruby ​​/ autres scripts. J'ai utilisé popen2 en Python ou open3 en Perl pour ce faire.

MISE À JOUR: voici un one-liner utilisant jmxterm:

echo run -b java.lang:type=Memory gc | java -jar jmxterm-1.0-alpha-4-uber.jar -n -l host:port

346

Depuis JDK 7, vous pouvez utiliser l'outil de commande JDK 'jcmd' tel que:

jcmd <pid> GC.run


22
Pourquoi vous ne me parlez pas de ces choses?! :)
noahlz

2
si vous obtenez une "AttachNotSupportedException: Unable to open socket file", voir mon ajout à cette réponse
Thomas Rebele

Et si vous obtenez Explicit GC is disabled, no GC has been performedcela peut être dû à l' -XX:+DisableExplicitGCargument VM. Voir: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth

Cela fonctionnera uniquement pour Oracle JDK, cela ne fonctionnera pas pour open-jdk.
Ali Saleh le

104

Si vous exécutez jmap -histo:live <pid>, cela forcera un GC complet sur le tas avant d'imprimer quoi que ce soit.


3
forcer un garbage collection sur tous les javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak

1
Où est-ce documenté? Qu'en est-il sans: en direct (par exemple quand -F est nécessaire)?
nafg

7
Bonjour du mystérieux avenir de 2014. jcmdest maintenant le bon outil pour le travail.
noahlz

16

Ajout à la réponse de user3198490 . L'exécution de cette commande peut vous donner le message d'erreur suivant:

$ jcmd 1805 GC.run    
[16:08:01]
1805:
com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
...

Cela peut être résolu à l'aide de cette réponse stackoverflow

sudo -u <process_owner> jcmd <pid> GC.run

<process_owner>est l'utilisateur qui exécute le processus avec PID <pid>. Vous pouvez obtenir les deux depuis topouhtop


Qu'en est-il de ce qui suit? Même chose? java.io.IOException: Operation not permitted
dhockey

Je n'ai pas encore rencontré ce message d'erreur. Peut-être que ça marche avec sudo -u <process_owner> jcmd <pid> GC.run, pourriez-vous essayer? La commande devrait être sûre
Thomas Rebele

J'aurais mais je n'ai pas d'accès sudo sur cette machine.
dhockey

L'outil fonctionne correctement. Vous n'avez tout simplement pas les bonnes autorisations dans le système d'exploitation pour l'exécuter. La même chose s'applique aux autres applications, même n'utilisant pas Java.
aled le

6

Il y a quelques autres solutions (beaucoup de bonnes ici déjà):

  • Écrivez un petit code pour accéder au MemoryMBean et appelez gc().
  • Utilisation d'un client JMX en ligne de commande (comme cmdline-jmxclient , jxmterm ) et exécutez l' gc()opération sur le MemoryMBean

L'exemple suivant concerne le cmdline-jmxclient:

$ java -jar cmdline-jmxclient-0.10.3.jar - localhost:3812 'java.lang:type=Memory' gc

C'est bien car ce n'est qu'une ligne et vous pouvez la mettre dans un script très facilement.


5

pour Linux:

$ jcmd $(pgrep java) GC.run

jcmdest fourni avec le JDK, $(pgrep java)obtient l'ID de processus de java


Cela ne fonctionnera que s'il y a un processus Java en cours d'exécution, semble-t-il. Sinon, il interprétera le deuxième PID comme la commande pour jcmd qui n'est évidemment pas reconnue et lancera une erreur.
Cas Eliëns

0

Je ne pense pas qu'il existe une option de ligne de commande pour la même chose.

Vous devrez utiliser jvisualvm / jconsole pour la même chose.

Je vous suggère plutôt d'utiliser ces outils pour identifier, pourquoi votre programme est riche en mémoire.

Quoi qu'il en soit, vous ne devriez pas forcer GC, car cela perturberait certainement l'algorithme GC et ralentirait votre programme.


0

Si vous utilisez jolokia avec votre application, vous pouvez déclencher un garbage collection avec cette commande:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc

-10

juste:

kill -SIGQUIT <PID>

4
Cela déclenchera un vidage de tas et non un ramassage des ordures
Dror Bereznitsky

au moins est solaris il fait une force GC.
Amin Abbaspour le

2
Même pas sous Solaris, SIGQUIT ne déclenchera ni GC ni vidage de tas. SIGQUIT déclenchera un vidage de thread uniquement pour HotSpot. Pour IBM JVM, il est configurable.
Mircea Vutcovici

Ne déclenchera pas GC, imprimez simplement la trace de la pile.
Elad Tabak
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.