Bagaimana Anda Memaksa Pengumpulan Sampah dari Shell?

106

Jadi saya melihat tumpukan dengan jmap di kotak jarak jauh dan saya ingin memaksa pengumpulan sampah di atasnya. Bagaimana Anda melakukan ini tanpa masuk ke jvisualvm atau jconsole dan teman-teman?

Saya tahu Anda seharusnya tidak melakukan praktik pengumpulan sampah secara paksa - Anda harus mencari tahu mengapa tumpukan itu besar / bertambah.

Saya juga menyadari System.GC () sebenarnya tidak memaksa pengumpulan sampah - itu hanya memberi tahu GC bahwa Anda ingin hal itu terjadi.

Apakah ada cara untuk melakukan ini dengan mudah? Beberapa aplikasi baris perintah yang saya lewatkan?

eyberg
sumber
Tidak sama dengan stackoverflow.com/questions/1481178/…
Raedwald

Jawaban:

25

Anda dapat melakukannya melalui program jmxterm gratis .

Nyalakan seperti ini:

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

Dari sana, Anda dapat terhubung ke host dan memicu 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

Lihat dokumen di situs web jmxterm untuk informasi tentang menyematkannya di skrip bash / perl / ruby ​​/ lainnya. Saya telah menggunakan popen2 dengan Python atau open3 di Perl untuk melakukan ini.

UPDATE: inilah satu baris menggunakan jmxterm:

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

Sejak JDK 7 Anda dapat menggunakan alat perintah JDK 'jcmd' seperti:

jcmd <pid> GC.run

pengguna3198490
sumber
22
Mengapa kalian tidak memberitahuku tentang hal-hal ini ?! :)
noahlz
2
jika Anda mendapatkan "AttachNotSupportedException: Unable to open socket file", lihat tambahan saya untuk jawaban ini
Thomas Rebele
Dan jika Anda mendapatkannya Explicit GC is disabled, no GC has been performed, mungkin karena -XX:+DisableExplicitGCargumen VM. Lihat: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth
Ini hanya akan berfungsi untuk Oracle JDK, tidak akan berfungsi untuk open-jdk.
Ali Saleh
104

Jika Anda menjalankan jmap -histo:live <pid>, itu akan memaksa GC penuh di heap sebelum mencetak apa pun.

Will Hartung
sumber
3
memaksa pengumpulan sampah di semua javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak
1
Dimana itu didokumentasikan? Bagaimana dengan tanpa: live (misalnya saat -F diperlukan)?
nafg
7
Halo dari masa depan misterius 2014. jcmdsekarang alat yang tepat untuk pekerjaan itu.
noahlz
16

Selain user3198490 jawaban 's. Menjalankan perintah ini mungkin memberi Anda pesan kesalahan berikut:

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

Ini dapat diselesaikan dengan bantuan jawaban stackoverflow ini

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

di mana <process_owner>pengguna yang menjalankan proses dengan PID <pid>. Anda bisa mendapatkan keduanya dari topatauhtop

Thomas Rebele
sumber
Bagaimana dengan berikut ini? Hal yang sama? java.io.IOException: Operation not permitted
dhockey
Saya belum menemukan pesan kesalahan ini. Mungkin berhasil sudo -u <process_owner> jcmd <pid> GC.run, bisakah Anda mencoba? Perintah itu harus aman
Thomas Rebele
Saya ingin tetapi saya tidak memiliki akses sudo di mesin itu.
dhockey
Alat tersebut bekerja dengan benar. Anda hanya tidak memiliki izin yang tepat di sistem operasi untuk menjalankannya. Hal yang sama berlaku untuk aplikasi lain, bahkan tidak menggunakan Java.
aled
6

Ada beberapa solusi lain (sudah banyak yang bagus di sini):

  • Tulis sedikit kode untuk mengakses MemoryMBean dan menelepongc() .
  • Menggunakan klien JMX baris perintah (seperti cmdline-jmxclient , jxmterm ) dan menjalankan gc()operasi pada MemoryMBean

Contoh berikut adalah untuk cmdline-jmxclient:

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

Ini bagus karena hanya satu baris dan Anda dapat memasukkannya ke dalam skrip dengan sangat mudah.

Sang Alkemis
sumber
5

untuk linux:

$ jcmd $(pgrep java) GC.run

jcmddikemas dengan JDK, $(pgrep java)mendapatkan ID proses java

Xuejun Liu
sumber
Ini hanya akan bekerja ketika ada satu proses java yang berjalan. Jika tidak, itu akan menafsirkan PID kedua sebagai perintah untuk jcmd yang jelas tidak dikenali dan menimbulkan kesalahan.
Cas Eliëns
0

Saya tidak berpikir ada opsi baris perintah untuk hal yang sama.

Anda perlu menggunakan jvisualvm / jconsole untuk hal yang sama.

Saya lebih menyarankan Anda untuk menggunakan alat ini untuk mengidentifikasi, mengapa program Anda memiliki memori tinggi.

Bagaimanapun Anda tidak boleh memaksa GC, karena akan mengganggu algoritma GC dan membuat program Anda lambat.

YoK
sumber
0

Jika Anda menggunakan jolokia dengan aplikasi Anda, Anda dapat memicu pengumpulan sampah dengan perintah ini:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc
mesin debu
sumber
-10

hanya:

kill -SIGQUIT <PID>
Amin Abbaspour
sumber
4
Ini akan memicu heap dump, bukan pengumpulan sampah
Dror Bereznitsky
setidaknya adalah solaris itu melakukan GC gaya.
Amin Abbaspour
2
Bahkan di Solaris, SIGQUIT tidak akan memicu GC atau heap dump. SIGQUIT akan memicu thread dump hanya untuk HotSpot. Untuk IBM JVM ini dapat dikonfigurasi.
Mircea Vutcovici
Tidak akan memicu GC, cukup cetak jejak tumpukan.
Elad Tabak