it-swarm-id.com

Kapan System.gc () melakukan sesuatu?

Saya tahu bahwa pengumpulan sampah otomatis di Jawa. Tapi saya mengerti bahwa jika Anda memanggil System.gc() dalam kode Anda bahwa JVM mungkin atau mungkin tidak memutuskan untuk melakukan pengumpulan sampah pada saat itu. Bagaimana cara kerjanya tepatnya? Atas dasar/parameter apa tepatnya JVM memutuskan untuk melakukan (atau tidak melakukan) GC ketika melihat System.gc()?

Apakah ada contoh dalam hal ini ide yang baik untuk memasukkan ini ke dalam kode Anda?

111
harry

Dalam prakteknya, itu biasanya memutuskan untuk melakukan pengumpulan sampah. Jawabannya bervariasi tergantung pada banyak faktor, seperti JVM yang Anda jalankan, mode apa yang digunakan, dan algoritma pengumpulan sampah yang digunakannya.

Saya tidak akan bergantung pada kode Anda. Jika JVM hendak melempar OutOfMemoryError, memanggil System.gc () tidak akan menghentikannya, karena pemulung akan berusaha untuk membebaskan sebanyak mungkin sebelum ia pergi ke ekstrim itu. Satu-satunya waktu saya melihatnya digunakan dalam praktek adalah dalam IDE di mana itu dilampirkan ke tombol yang dapat diklik pengguna, tetapi bahkan di sana itu tidak terlalu berguna.

58
jodonnell

Satu-satunya contoh yang bisa saya pikirkan di mana masuk akal untuk memanggil System.gc () adalah ketika membuat profil aplikasi untuk mencari kemungkinan kebocoran memori. Saya percaya para profiler memanggil metode ini sebelum mengambil snapshot memori.

29

Java Spesifikasi Bahasa tidak menjamin bahwa JVM akan memulai GC ketika Anda memanggil System.gc(). Ini adalah alasan dari ini "mungkin atau mungkin tidak memutuskan untuk melakukan GC pada saat itu".

Sekarang, jika Anda melihat kode sumber OpenJDK , yang merupakan tulang punggung Oracle JVM, Anda akan melihat bahwa panggilan ke System.gc() tidak memulai siklus GC. Jika Anda menggunakan JVM lain, seperti J9, Anda harus memeriksa dokumentasinya untuk mengetahui jawabannya. Misalnya, JVM Azul memiliki pemulung yang berjalan terus menerus, jadi panggilan ke System.gc() tidak akan melakukan apa pun

Beberapa jawaban lain menyebutkan memulai GC di JConsole atau VisualVM. Pada dasarnya, alat-alat ini melakukan panggilan jarak jauh ke System.gc().

Biasanya, Anda tidak ingin memulai siklus pengumpulan sampah dari kode Anda, karena ini mengacaukan semantik aplikasi Anda. Aplikasi Anda melakukan beberapa hal bisnis, JVM menangani manajemen memori. Anda harus memisahkan masalah tersebut (jangan membuat aplikasi Anda melakukan manajemen memori, fokus pada bisnis).

Namun, ada beberapa kasus di mana panggilan ke System.gc() mungkin dapat dimengerti. Pertimbangkan, misalnya, microbenchmark. Tidak seorang pun ingin memiliki siklus GC terjadi di tengah microbenchmark. Jadi, Anda dapat memicu siklus GC antara setiap pengukuran untuk memastikan setiap pengukuran dimulai dengan tumpukan kosong.

24
Pierre Laporte

Anda tidak memiliki kendali atas GC di Java - the VM yang diputuskan. Saya tidak pernah menemukan kasus di mana System.gc() dibutuhkan . Karena System.gc() hanya memanggil SUGGESTS bahwa VM melakukan pengumpulan sampah dan juga melakukan pengumpulan sampah LENGKAP (generasi lama dan baru dalam tumpukan multi-generasi), maka sebenarnya dapat menyebabkan LEBIH BANYAK siklus cpu untuk dikonsumsi daripada yang diperlukan.

Dalam beberapa kasus, masuk akal untuk menyarankan VM bahwa ia melakukan pengumpulan penuh SEKARANG karena Anda mungkin tahu aplikasi akan diam selama beberapa menit berikutnya sebelum terjadi pengangkatan berat. Sebagai contoh, tepat setelah inisialisasi banyak objek sementara selama startup aplikasi (mis., Saya baru saja mencatat satu TON info, dan saya tahu saya tidak akan mendapatkan banyak aktivitas selama satu menit atau lebih). Pikirkan sebuah IDE seperti memulai Eclipse - ini memang banyak yang harus diinisialisasi, jadi mungkin segera setelah inisialisasi, masuk akal untuk melakukan gc penuh pada saat itu.

23
DustinB

Anda harus sangat berhati-hati jika menelepon System.gc(). Menyebutnya dapat menambah masalah kinerja yang tidak perlu ke aplikasi Anda, dan itu tidak dijamin untuk benar-benar melakukan pengumpulan. Sebenarnya dimungkinkan untuk menonaktifkan System.gc() eksplisit melalui argumen Java_-XX:+DisableExplicitGC_.

Saya sangat merekomendasikan membaca dokumen yang tersedia di Java HotSpot Garbage Collection untuk detail lebih lanjut tentang pengumpulan sampah.

17

System.gc() diimplementasikan oleh VM, dan apa yang dilakukannya adalah implementasi spesifik. Pelaksana bisa saja kembali dan tidak melakukan apa pun, misalnya.

Mengenai kapan mengeluarkan koleksi manual, satu-satunya waktu ketika Anda mungkin ingin melakukan ini adalah ketika Anda meninggalkan koleksi besar yang berisi banyak koleksi yang lebih kecil - misalnya Map<String,<LinkedList>> - dan Anda ingin mencoba dan mengambil perf hit saat itu juga, tetapi untuk sebagian besar, Anda tidak perlu khawatir tentang hal itu. GC tahu lebih baik daripada Anda - sayangnya - sebagian besar waktu.

10
Patrick

Jika Anda menggunakan buffer memori langsung, JVM tidak menjalankan GC untuk Anda bahkan jika Anda kehabisan memori langsung.

Jika Anda memanggil ByteBuffer.allocateDirect() dan Anda mendapatkan OutOfMemoryError, Anda dapat menemukan panggilan ini baik-baik saja setelah memicu GC secara manual.

8
Peter Lawrey

Kebanyakan JVM akan memulai GC (tergantung pada -XX: DiableExplicitGC dan -XX: + ExplicitGCInvokesConcurrent switch). Namun spesifikasinya kurang terdefinisi dengan baik untuk memungkinkan implementasi yang lebih baik di kemudian hari.

Spesifikasi perlu diklarifikasi: Bug # 6668279: (spec) System.gc () harus menunjukkan bahwa kami tidak merekomendasikan penggunaan dan tidak menjamin perilak

Secara internal metode gc digunakan oleh RMI dan NIO, dan mereka membutuhkan eksekusi sinkron, yang: saat ini sedang dalam diskusi:

Bug # 5025281: Izinkan System.gc () untuk memicu koleksi penuh bersamaan (bukan stop-the-dunia)

5
eckes

Garbage Collection bagus di Java, jika kita menjalankan Perangkat Lunak yang dikodekan dalam Java di Desktop/laptop/server. Anda dapat memanggil System.gc() atau Runtime.getRuntime().gc() di Java.

Perhatikan bahwa tidak ada panggilan yang dijamin untuk melakukan apa pun. Mereka hanya saran bagi jvm untuk menjalankan Pengumpul Sampah. Terserah pada JVM apakah menjalankan GC atau tidak. Jadi, jawaban singkat: kita tidak tahu kapan itu berjalan. Jawaban yang lebih panjang: JVM akan menjalankan gc jika ada waktu untuk itu.

Saya percaya, hal yang sama berlaku untuk Android. Namun, ini mungkin memperlambat sistem Anda.

2
Naveen

Biasanya, VM akan melakukan pengumpulan sampah secara otomatis sebelum melempar OutOfMemoryException, jadi menambahkan panggilan eksplisit tidak akan membantu kecuali dalam hal itu mungkin menggerakkan kinerja hit ke saat sebelumnya.

Namun, saya pikir saya menemukan kasus yang mungkin relevan. Saya tidak yakin, karena saya belum menguji apakah ada efek:

Ketika Anda memetakan file memori, saya percaya panggilan map () melempar IOException ketika blok memori yang cukup besar tidak tersedia. Kumpulan sampah tepat sebelum map () file mungkin membantu mencegahnya, saya pikir. Bagaimana menurut anda?

2
Vashek

kita tidak pernah bisa memaksakan pengumpulan sampah. System.gc hanya menyarankan vm untuk pengumpulan sampah, namun, benar-benar jam berapa mekanisme berjalan, tidak ada yang tahu, ini seperti yang dinyatakan oleh spesifikasi JSR.

2
lwpro2

Ada BANYAK yang bisa dikatakan dalam meluangkan waktu untuk menguji berbagai pengaturan pengumpulan sampah, tetapi seperti yang disebutkan di atas biasanya tidak berguna untuk melakukannya.

Saat ini saya sedang mengerjakan proyek yang melibatkan lingkungan terbatas memori dan jumlah data yang relatif besar - ada beberapa bagian besar data yang mendorong lingkungan saya hingga batasnya, dan meskipun saya bisa menurunkan penggunaan memori jadi bahwa secara teori itu seharusnya bekerja dengan baik, saya masih akan mendapatkan banyak kesalahan ruang --- pilihan GC verbose menunjukkan kepada saya bahwa ia mencoba mengumpulkan sampah, tetapi tidak berhasil. Dalam debugger, saya bisa melakukan System.gc () dan tentu saja akan ada "banyak" memori yang tersedia ... tidak banyak tambahan, tetapi cukup.

Akibatnya, satu-satunya waktu aplikasi saya memanggil System.gc () adalah ketika akan memasuki segmen kode di mana buffer besar yang diperlukan untuk memproses data akan dialokasikan, dan tes pada memori bebas yang tersedia menunjukkan bahwa saya tidak dijamin memilikinya. Secara khusus, saya melihat lingkungan 1gb di mana setidaknya 300mb ditempati oleh data statis, dengan sebagian besar data non-statis terkait dengan eksekusi kecuali ketika data yang sedang diproses setidaknya 100-200 MB pada sumber. Itu semua adalah bagian dari proses konversi data otomatis, sehingga semua data ada untuk jangka waktu yang relatif singkat dalam jangka panjang.

Sayangnya, sementara informasi tentang berbagai opsi untuk menyetel pengumpul sampah tersedia, tampaknya sebagian besar merupakan proses eksperimental dan spesifik tingkat yang lebih rendah yang diperlukan untuk memahami bagaimana menangani situasi khusus ini tidak mudah diperoleh.

Semua itu dikatakan, meskipun saya menggunakan System.gc (), saya masih terus menyetel menggunakan parameter baris perintah dan berhasil meningkatkan waktu pemrosesan keseluruhan aplikasi saya dengan jumlah yang relatif signifikan, meskipun tidak dapat melupakan batu sandungan yang ditimbulkan oleh bekerja dengan blok data yang lebih besar. Yang sedang berkata, System.gc () adalah alat .... alat yang sangat tidak bisa diandalkan, dan jika Anda tidak berhati-hati dengan cara menggunakannya, Anda akan berharap itu tidak berfungsi lebih sering daripada tidak.

2
Kyune

Pendeknya:

Parameter tergantung VM.

Contoh penggunaan - tidak dapat memikirkan satu untuk aplikasi runtime/produksi, tetapi berguna untuk menjalankannya untuk beberapa memanfaatkan profil, seperti memanggil

// test run #1
test();
for (int i=0; i<10; i++) { 
// calling repeatedly to increase chances of a clean-up
  System.gc(); 
}
// test run #2
test();
1
mataal

Jika Anda ingin tahu apakah System.gc() Anda dipanggil, Anda dapat dengan pembaruan Java 7 yang baru 4 mendapatkan pemberitahuan ketika JVM melakukan Pengumpulan Sampah.

Saya tidak 100% yakin bahwa kelas GarbageCollectorMXBean diperkenalkan di Java 7 pembaruan 4, karena saya tidak dapat menemukannya di catatan rilis, tetapi saya menemukan informasinya di the javaperformancetuning . com situs

1
Shervin Asgari

Menurut Thinking in Java oleh Bruce Eckel, satu kasus penggunaan untuk eksplisit System.gc () panggilan adalah ketika Anda ingin memaksakan finalisasi, yaitu.n. panggilan ke menyelesaikan metode.

0
Asterisk

Saya tidak bisa memikirkan contoh khusus ketika itu baik untuk menjalankan GC eksplisit.

Secara umum, menjalankan GC eksplisit sebenarnya dapat menyebabkan lebih banyak kerugian daripada kebaikan, karena gc eksplisit akan memicu koleksi penuh, yang memakan waktu lebih lama secara signifikan saat melewati setiap objek. Jika gc eksplisit ini berakhir dipanggil berulang kali dapat dengan mudah menyebabkan aplikasi lambat karena banyak waktu dihabiskan untuk menjalankan GC penuh.

Atau jika pergi ke tumpukan dengan penganalisa tumpukan dan Anda mencurigai komponen perpustakaan untuk memanggil GC eksplisit Anda dapat mematikannya menambahkan: gc = -XX: + DisableExplicitGC ke parameter JVM.

0
zxcv

ketika system.gc bekerja, itu akan menghentikan dunia: semua respone dihentikan sehingga pemulung dapat memindai setiap objek untuk memeriksa apakah perlu dihapus. jika aplikasi adalah proyek web, semua permintaan dihentikan sampai gc selesai, dan ini akan menyebabkan proyek web Anda tidak dapat berfungsi dalam monent.

0
fleture