Wie erzwingen Sie die Speicherbereinigung aus der Shell?


106

Ich betrachte also einen Haufen mit jmap auf einer Remote-Box und möchte die Speicherbereinigung erzwingen. Wie machst du das, ohne in jvisualvm oder jconsole und Freunde einzutauchen?

Ich weiß, Sie sollten nicht in der Praxis sein, die Speicherbereinigung zu erzwingen - Sie sollten nur herausfinden, warum der Haufen groß ist / wächst.

Mir ist auch klar, dass System.GC () die Speicherbereinigung nicht erzwingt - es teilt dem GC lediglich mit, dass dies geschehen soll.

Gibt es eine Möglichkeit, dies einfach zu tun? Irgendeine Kommandozeilen-App, die mir fehlt?


Antworten:


25

Sie können dies über das kostenlose Programm jmxterm tun .

Starten Sie es so:

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

Von dort aus können Sie eine Verbindung zu einem Host herstellen und GC auslösen:

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

Informationen zum Einbetten in bash / perl / ruby ​​/ other-Skripten finden Sie in den Dokumenten auf der jmxterm-Website. Ich habe dazu popen2 in Python oder open3 in Perl verwendet.

UPDATE: Hier ist ein Einzeiler mit jmxterm:

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

346

Seit JDK 7 können Sie das JDK-Befehlstool 'jcmd' verwenden, z.

jcmd <pid> GC.run


22
Warum erzählen mir die Leute nicht von diesen Dingen?! :)
Noahlz

2
Wenn Sie eine "AttachNotSupportedException: Socket-Datei kann nicht geöffnet werden" erhalten, lesen Sie meinen Zusatz zu dieser Antwort
Thomas Rebele

Und wenn Sie dies erhalten Explicit GC is disabled, no GC has been performed, liegt dies möglicherweise am -XX:+DisableExplicitGCVM-Argument. Siehe: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth

Dies funktioniert nur für Oracle JDK, nicht für Open-JDK.
Ali Saleh

104

Wenn Sie ausführen jmap -histo:live <pid>, wird ein vollständiger GC auf dem Heap erzwungen, bevor etwas ausgedruckt wird.


3
Erzwinge eine Speicherbereinigung für alle Javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak

1
Wo ist das dokumentiert? Was ist ohne: leben (zB wenn -F benötigt wird)?
Nafg

7
Hallo aus der mysteriösen Zukunft von 2014. jcmdist jetzt das richtige Werkzeug für den Job.
Noahlz

15

Ergänzung zur Antwort von user3198490 . Wenn Sie diesen Befehl ausführen, wird möglicherweise die folgende Fehlermeldung angezeigt:

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

Dies kann mit Hilfe dieser Stackoverflow-Antwort gelöst werden

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

wo <process_owner>ist der Benutzer, der den Prozess mit PID läuft <pid>. Sie können beide von topoder bekommenhtop


Was ist mit den folgenden? Gleiche Sache? java.io.IOException: Operation not permitted
Dhockey

Ich habe diese Fehlermeldung noch nicht gefunden. Vielleicht funktioniert es mit sudo -u <process_owner> jcmd <pid> GC.run, könnten Sie es versuchen? Der Befehl sollte sicher sein
Thomas Rebele

Ich hätte, aber ich habe keinen Sudo-Zugriff auf diesem Computer.
Dhockey

Das Tool funktioniert ordnungsgemäß. Sie haben einfach nicht die richtigen Berechtigungen im Betriebssystem, um es auszuführen. Gleiches gilt für andere Anwendungen, auch wenn Java nicht verwendet wird.
Aled

6

Es gibt noch ein paar andere Lösungen (viele gute hier schon):

Das folgende Beispiel bezieht sich auf den Befehl cmdline-jmxclient:

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

Das ist schön, weil es nur eine Zeile ist und Sie es wirklich einfach in ein Skript einfügen können.


4

für Linux:

$ jcmd $(pgrep java) GC.run

jcmdwird mit dem JDK gepackt, $(pgrep java)erhält die Prozess-ID von Java


Dies funktioniert nur, wenn anscheinend ein Java-Prozess ausgeführt wird. Andernfalls wird die zweite PID als Befehl für jcmd interpretiert, der offensichtlich nicht erkannt wird, und es wird ein Fehler ausgegeben.
Cas Eliëns

0

Ich glaube nicht, dass es dafür eine Befehlszeilenoption gibt.

Sie müssen dafür jvisualvm / jconsole verwenden.

Ich würde Ihnen eher empfehlen, diese Tools zu verwenden, um zu identifizieren, warum Ihr Programm viel Speicherplatz hat.

Auf jeden Fall sollten Sie GC nicht erzwingen, da dies den GC-Algorithmus sicherlich stören und Ihr Programm verlangsamen würde.


0

Wenn Sie jolokia mit Ihrer Anwendung verwenden, können Sie mit diesem Befehl eine Garbage Collection auslösen:

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

-10

gerade:

kill -SIGQUIT <PID>

4
Dies wird eine Heap-Dump nicht Garbage Collection auslösen
Dror Bereznitsky

Zumindest ist Solaris eine Kraft-GC.
Amin Abbaspour

2
Nicht einmal in Solaris löst SIGQUIT weder einen GC noch einen Heap-Dump aus. SIGQUIT löst nur für HotSpot einen Thread-Dump aus. Für IBM JVM ist es konfigurierbar.
Mircea Vutcovici

Löst keine GC aus, drucken Sie einfach den Stack-Trace.
Elad Tabak
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.