Come si forza la raccolta dei rifiuti dalla shell?


106

Quindi sto guardando un mucchio con jmap su un box remoto e voglio forzare la raccolta dei rifiuti su di esso. Come puoi farlo senza entrare in jvisualvm o jconsole e amici?

So che non dovresti essere nella pratica di forzare la raccolta dei rifiuti - dovresti solo capire perché l'heap è grande / in crescita.

Mi rendo anche conto che System.GC () in realtà non forza la garbage collection, ma dice semplicemente al GC che desideri che si verifichi.

Detto questo, c'è un modo per farlo facilmente? Qualche app della riga di comando che mi manca?


Risposte:


25

Puoi farlo tramite il programma gratuito jmxterm .

Accendilo in questo modo:

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

Da lì, puoi connetterti a un host e attivare 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

Guarda la documentazione sul sito web jmxterm per informazioni su come incorporarlo in bash / perl / ruby ​​/ altri script. Ho usato popen2 in Python o open3 in Perl per fare questo.

AGGIORNAMENTO: ecco un one-liner che utilizza jmxterm:

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

346

A partire da JDK 7 puoi utilizzare lo strumento di comando JDK 'jcmd' come:

jcmd <pid> GC.run


22
Perché non mi parlate di queste cose ?! :)
noahlz

2
se ottieni una "AttachNotSupportedException: Unable to open socket file", vedi la mia aggiunta a questa risposta
Thomas Rebele

E se stai ottenendo Explicit GC is disabled, no GC has been performedciò potrebbe essere dovuto -XX:+DisableExplicitGCall'argomento VM. Vedi: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth

Funzionerà solo per Oracle JDK, non funzionerà per open-jdk.
Ali Saleh

104

Se esegui jmap -histo:live <pid>, questo forzerà un GC completo sull'heap prima che stampi qualcosa.


3
forza una garbage collection su tutti i java: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak

1
Dov'è documentato? E senza: live (ad es. Quando è necessario -F)?
nafg

7
Ciao dal misterioso futuro del 2014. jcmdora è lo strumento giusto per il lavoro.
noahlz

16

Aggiunta alla risposta di user3198490 . L'esecuzione di questo comando potrebbe fornire il seguente messaggio di errore:

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

Questo può essere risolto con l'aiuto di questa risposta di stackoverflow

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

dov'è <process_owner>l'utente che esegue il processo con PID <pid>. Puoi ottenere entrambi da topohtop


E quanto segue? Stessa cosa? java.io.IOException: Operation not permitted
dhockey

Non ho ancora riscontrato questo messaggio di errore. Forse funziona consudo -u <process_owner> jcmd <pid> GC.run , potresti provare? Il comando dovrebbe essere sicuro
Thomas Rebele

Avrei ma non ho accesso sudo su quella macchina.
dhockey

Lo strumento funziona correttamente. Semplicemente non hai le autorizzazioni giuste nel sistema operativo per eseguirlo. Lo stesso vale per altre applicazioni, anche se non utilizzano Java.
aled

6

Ci sono alcune altre soluzioni (molte buone già qui):

  • Scrivi un piccolo codice per accedere a MemoryMBean e chiama gc().
  • Utilizzando un client JMX della riga di comando (come cmdline-jmxclient , jxmterm ) ed eseguire l' gc()operazione su MemoryMBean

L'esempio seguente è per cmdline-jmxclient:

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

Questo è bello perché è solo una riga e puoi metterlo in uno script molto facilmente.


5

per linux:

$ jcmd $(pgrep java) GC.run

jcmdviene fornito con JDK, $(pgrep java)ottiene l'ID di processo di java


Questo funzionerà solo quando sembra che sia in esecuzione un processo Java. Altrimenti interpreterà il secondo PID come il comando per jcmd che ovviamente non è riconosciuto e genererà un errore.
Cas Eliëns

0

Non penso che ci sia alcuna opzione della riga di comando per lo stesso.

Dovrai usare jvisualvm / jconsole per lo stesso.

Preferirei suggerirti di utilizzare questi strumenti per identificare il motivo per cui il tuo programma è ricco di memoria.

Ad ogni modo non dovresti forzare GC, poiché sicuramente disturberebbe l'algoritmo GC e rallenterebbe il tuo programma.


0

Se stai usando jolokia con la tua applicazione, puoi attivare una garbage collection con questo comando:

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

-10

appena:

kill -SIGQUIT <PID>

4
Questo attiverà un dump dell'heap e non una garbage collection
Dror Bereznitsky

almeno è solaris che fa una forza GC.
Amin Abbaspour

2
Nemmeno in Solaris, SIGQUIT non attiverà né un GC né un heap dump. SIGQUIT attiverà un dump del thread solo per HotSpot. Per IBM JVM è configurabile.
Mircea Vutcovici

Non attiverà GC, stampa solo la traccia dello stack.
Elad Tabak
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.