¿Cómo se fuerza la recolección de basura del Shell?

106

Así que estoy viendo un montón con jmap en una caja remota y quiero forzar la recolección de basura en él. ¿Cómo puede hacer esto sin entrar en jvisualvm o jconsole and friends?

Sé que no debería estar en la práctica de forzar la recolección de basura; solo debe averiguar por qué el montón es grande / crece.

También me doy cuenta de que System.GC () en realidad no fuerza la recolección de basura, solo le dice al GC que le gustaría que ocurra.

Habiendo dicho eso, ¿hay alguna manera de hacer esto fácilmente? ¿Alguna aplicación de línea de comandos que me falta?

Eyberg
fuente
No es lo mismo que stackoverflow.com/questions/1481178/…
Raedwald

Respuestas:

25

Puede hacerlo a través del programa gratuito jmxterm .

Enciéndelo así:

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

Desde allí, puede conectarse a un host y activar 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

Consulte los documentos del sitio web jmxterm para obtener información sobre cómo incrustar esto en bash / perl / ruby ​​/ otros scripts. He usado popen2 en Python o open3 en Perl para hacer esto.

ACTUALIZACIÓN: aquí hay una sola línea usando jmxterm:

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

Desde JDK 7, puede usar la herramienta de comando JDK 'jcmd' como:

jcmd <pid> GC.run

usuario3198490
fuente
22
¡¿Por qué no me cuentan estas cosas ?! :)
noahlz
2
si obtiene una "AttachNotSupportedException: No se puede abrir el archivo de socket", vea mi adición a esta respuesta
Thomas Rebele
Y si lo está obteniendo, Explicit GC is disabled, no GC has been performedpodría deberse al -XX:+DisableExplicitGCargumento de VM. Ver: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth
Esto funcionará solo para Oracle JDK, no funcionará para open-jdk.
Ali Saleh
104

Si lo ejecuta jmap -histo:live <pid>, forzará un GC completo en el montón antes de que imprima algo.

Will Hartung
fuente
3
forzar una recolección de basura en todos los javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak
1
¿Dónde está eso documentado? ¿Qué pasa sin: en vivo (por ejemplo, cuando se necesita -F)?
nafg
7
Hola desde el misterioso futuro de 2014. jcmdAhora es la herramienta adecuada para el trabajo.
noahlz
16

Adición a la respuesta del usuario3198490 . La ejecución de este comando puede generar el siguiente mensaje de error:

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

Esto se puede resolver con la ayuda de esta respuesta de stackoverflow

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

donde <process_owner>es el usuario que ejecuta el proceso con PID <pid>. Puede obtener tanto de topohtop

Thomas Rebele
fuente
¿Qué pasa con lo siguiente? ¿La misma cosa? java.io.IOException: Operation not permitted
dhockey
Todavía no he encontrado este mensaje de error. Tal vez funcione sudo -u <process_owner> jcmd <pid> GC.run, ¿podrías intentarlo? El comando debe ser seguro
Thomas Rebele
Lo habría hecho, pero no tengo acceso a sudo en esa máquina.
Hockey
La herramienta funciona correctamente. Simplemente no tiene los permisos adecuados en el sistema operativo para ejecutarlo. Lo mismo se aplica a otras aplicaciones, incluso sin utilizar Java.
aled el
6

Hay algunas otras soluciones (ya hay muchas buenas aquí):

  • Escriba un pequeño código para acceder al MemoryMBean y llamar gc().
  • Usar un cliente JMX de línea de comandos (como cmdline-jmxclient , jxmterm ) y ejecutar la gc()operación en MemoryMBean

El siguiente ejemplo es para cmdline-jmxclient:

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

Esto es bueno porque es solo una línea y puedes ponerlo en un script muy fácilmente.

El alquimista
fuente
5

para linux:

$ jcmd $(pgrep java) GC.run

jcmdestá empaquetado con el JDK, $(pgrep java)obtiene el ID de proceso de java

Xuejun Liu
fuente
Esto solo funcionará cuando parezca que hay un proceso Java ejecutándose. De lo contrario, interpretará el segundo PID como el comando para jcmd que obviamente no se reconoce y arrojará un error.
Cas Eliëns
0

No creo que haya ninguna opción de línea de comando para lo mismo.

Necesitará usar jvisualvm / jconsole para lo mismo.

Preferiría sugerirle que utilice estas herramientas para identificar por qué su programa tiene mucha memoria.

De todos modos, no debe forzar GC, ya que ciertamente perturbaría el algoritmo GC y haría que su programa fuera lento.

YoK
fuente
0

Si está utilizando jolokia con su aplicación, puede activar una recolección de basura con este comando:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc
máquina de polvo
fuente
-10

sólo:

kill -SIGQUIT <PID>
Amin Abbaspour
fuente
4
Esto activará un volcado de pila, no una recolección de basura
Dror Bereznitsky
al menos es solaris hace una fuerza GC.
Amin Abbaspour
2
Ni siquiera en Solaris, SIGQUIT activará un GC ni un volcado de pila. SIGQUIT activará un volcado de hilo solo para HotSpot. Para IBM JVM, es configurable.
Mircea Vutcovici
No activará GC, solo imprime el seguimiento de la pila.
Elad Tabak