Jak wymusić zbieranie śmieci z powłoki?

106

Tak więc patrzę na stertę z jmap na zdalnym pudełku i chcę wymusić na niej zbieranie śmieci. Jak to zrobić bez zaglądania do jvisualvm lub jconsole i przyjaciół?

Wiem, że nie powinieneś ćwiczyć wymuszania zbierania śmieci - powinieneś po prostu dowiedzieć się, dlaczego sterta jest duża / rośnie.

Zdaję sobie również sprawę, że System.GC () w rzeczywistości nie wymusza czyszczenia pamięci - po prostu mówi GC, że chcesz, aby to nastąpiło.

Powiedziawszy, że można to łatwo zrobić? Brakuje mi jakiejś aplikacji wiersza poleceń?

eyberg
źródło
To nie to samo, co stackoverflow.com/questions/1481178/…
Raedwald

Odpowiedzi:

25

Możesz to zrobić za pomocą bezpłatnego programu jmxterm .

Odpal to tak:

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

Stamtąd możesz połączyć się z hostem i uruchomić 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

Zajrzyj do dokumentacji na stronie jmxterm, aby uzyskać informacje na temat osadzania tego w skryptach bash / perl / ruby ​​/ innych. Użyłem do tego popen2 w Pythonie lub open3 w Perlu.

AKTUALIZACJA: oto jedna linijka wykorzystująca jmxterm:

echo run -b java.lang:type=Memory gc | java -jar jmxterm-1.0-alpha-4-uber.jar -n -l host:port
Harold L.
źródło
346

Od JDK 7 możesz użyć narzędzia poleceń JDK „jcmd”, takiego jak:

jcmd <pid> GC.run

user3198490
źródło
22
Dlaczego nie powiecie mi o tych rzeczach ?! :)
noahlz
2
jeśli pojawi się „AttachNotSupportedException: Unable to open socket file”, zobacz mój dodatek do tej odpowiedzi
Thomas Rebele,
A jeśli otrzymujesz Explicit GC is disabled, no GC has been performed, może to być spowodowane -XX:+DisableExplicitGCargumentem VM. Zobacz: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth
Będzie to działać tylko dla Oracle JDK, nie będzie działać dla open-jdk.
Ali Saleh
104

Jeśli uruchomisz jmap -histo:live <pid>, wymusi to pełny GC na stercie, zanim cokolwiek wydrukuje.

Will Hartung
źródło
3
wymuś czyszczenie pamięci na wszystkich javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak
1
Gdzie to jest udokumentowane? A co bez: na żywo (np. Gdy potrzebne jest -F)?
nafg
7
Witam z tajemniczej przyszłości 2014r. jcmdJest teraz odpowiednim narzędziem do tego zadania.
noahlz
16

Dodatek do user3198490 odpowiedź „s. Uruchomienie tego polecenia może spowodować wyświetlenie następującego komunikatu o błędzie:

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

Można to rozwiązać za pomocą tej odpowiedzi na temat przepełnienia stosu

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

gdzie <process_owner>jest użytkownikiem, który uruchamia proces z PID <pid>. Możesz uzyskać oba z toplubhtop

Thomas Rebele
źródło
A co z następującymi? Ta sama rzecz? java.io.IOException: Operation not permitted
dhockey
Nie napotkałem jeszcze tego komunikatu o błędzie. Może to działa sudo -u <process_owner> jcmd <pid> GC.run, czy mógłbyś spróbować? Polecenie powinno być bezpieczne
Thomas Rebele
Miałbym, ale nie mam dostępu do sudo na tym komputerze.
dhockey
Narzędzie działa poprawnie. Po prostu nie masz odpowiednich uprawnień w systemie operacyjnym, aby go wykonać. To samo dotyczy innych aplikacji, nawet nie korzystających z Javy.
aled
6

Jest kilka innych rozwiązań (już tutaj wiele dobrych):

  • Napisz mały kod, aby uzyskać dostęp do MemoryMBean i zadzwoń gc().
  • Używając klienta JMX wiersza poleceń (takiego jak cmdline-jmxclient , jxmterm ) i uruchom gc()operację na MemoryMBean

Poniższy przykład dotyczy cmdline-jmxclient:

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

Jest to fajne, ponieważ jest to tylko jedna linia i można ją bardzo łatwo umieścić w skrypcie.

Alchemik
źródło
5

dla linuxa:

$ jcmd $(pgrep java) GC.run

jcmdjest spakowany z JDK, $(pgrep java)pobiera identyfikator procesu java

Xuejun Liu
źródło
To zadziała tylko wtedy, gdy wygląda na to, że jest uruchomiony jeden proces Java. W przeciwnym razie zinterpretuje drugi PID jako polecenie dla jcmd, które oczywiście nie jest rozpoznane i zgłosi błąd.
Cas Eliëns
0

Myślę, że nie ma opcji wiersza poleceń do tego samego.

Będziesz musiał użyć jvisualvm / jconsole do tego samego.

Raczej zasugerowałbym ci użycie tych narzędzi do identyfikacji, dlaczego twój program ma dużo pamięci.

W każdym razie nie powinieneś wymuszać GC, ponieważ z pewnością zakłóciłoby to algorytm GC i spowolniłoby program.

YoK
źródło
0

Jeśli używasz jolokii w swojej aplikacji, możesz wyzwolić czyszczenie pamięci za pomocą tego polecenia:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc
maszyna do kurzu
źródło
-10

właśnie:

kill -SIGQUIT <PID>
Amin Abbaspour
źródło
4
Spowoduje to zrzut sterty, a nie zbieranie śmieci
Dror Bereznitsky
przynajmniej jest solaris, ma siłę GC.
Amin Abbaspour,
2
Nawet w Solarisie SIGQUIT nie wywoła ani GC, ani zrzutu sterty. SIGQUIT wyzwoli zrzut wątku tylko dla HotSpot. W przypadku IBM JVM jest to konfigurowalne.
Mircea Vutcovici
Nie uruchomi GC, po prostu wydrukuje ślad stosu.
Elad Tabak,