Saya tahu bahwa pengumpulan sampah dilakukan secara otomatis di Java. Tetapi saya mengerti bahwa jika Anda memanggil System.gc()
kode Anda, JVM mungkin atau mungkin tidak memutuskan untuk melakukan pengumpulan sampah pada saat itu. Bagaimana tepatnya ini bekerja? Atas dasar / parameter apa JVM memutuskan untuk melakukan (atau tidak melakukan) GC ketika JVM melihatnya System.gc()
?
Adakah contoh di mana ide yang baik untuk memasukkan ini ke dalam kode Anda?
java
garbage-collection
Michael
sumber
sumber
Jawaban:
Dalam praktiknya, biasanya memutuskan untuk melakukan pengumpulan sampah. Jawabannya bervariasi tergantung pada banyak faktor, seperti JVM yang Anda jalankan, modenya, dan algoritma pengumpulan sampah yang digunakannya.
Saya tidak akan bergantung padanya dalam kode Anda. Jika JVM akan melontarkan OutOfMemoryError, memanggil System.gc () tidak akan menghentikannya, karena pengumpul sampah akan berusaha membebaskan sebanyak mungkin sebelum menjadi ekstrim. Satu-satunya saat saya melihatnya digunakan dalam praktik adalah di IDE di mana ia dilampirkan ke tombol yang dapat diklik pengguna, tetapi bahkan di sana itu tidak terlalu berguna.
sumber
System.gc()
saat berada di layar pemuatan untuk video game. Pada titik itu, saya tidak akan terlalu peduli jika panggilan itu menghapus semua yang mungkin bisa dilakukan, atau tidak melakukan apa pun. Saya akan, bagaimanapun, lebih suka bahwa itu "mengeluarkan upaya untuk mendaur ulang objek yang tidak digunakan" selama layar pemuatan, daripada selama bermain game.Satu-satunya contoh yang dapat saya pikirkan di mana masuk akal untuk memanggil System.gc () adalah ketika membuat profil aplikasi untuk mencari kemungkinan kebocoran memori. Saya yakin para profiler memanggil metode ini sebelum mengambil snapshot memori.
sumber
Spesifikasi Bahasa Java tidak menjamin bahwa JVM akan memulai GC saat Anda memanggil
System.gc()
. Inilah alasannya "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 untuk
System.gc()
memulai siklus GC. Jika Anda menggunakan JVM lain, seperti J9, Anda harus memeriksa dokumentasinya untuk mengetahui jawabannya. Misalnya, JVM Azul memiliki pengumpul sampah yang berjalan terus menerus, jadi panggilan keSystem.gc()
tidak akan melakukan apa punBeberapa jawaban lain menyebutkan memulai GC di JConsole atau VisualVM. Pada dasarnya, alat ini melakukan panggilan jarak jauh
System.gc()
.Biasanya, Anda tidak ingin memulai siklus pengumpulan sampah dari kode Anda, karena itu 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, fokuslah pada bisnis).
Namun, ada beberapa kasus di mana panggilan ke
System.gc()
mungkin dapat dimengerti. Pertimbangkan, misalnya, tanda mikro. Tidak seorang pun ingin siklus GC terjadi di tengah-tengah microbenchmark. Jadi, Anda dapat memicu siklus GC di antara setiap pengukuran untuk memastikan setiap pengukuran dimulai dengan heap kosong.sumber
Anda tidak memiliki kendali atas GC di java - VM memutuskan. Aku tidak pernah berjalan di kasus mana
System.gc()
yang diperlukan . KarenaSystem.gc()
panggilan hanya MENYARANKAN bahwa VM melakukan pengumpulan sampah dan juga melakukan pengumpulan sampah LENGKAP (generasi lama dan baru dalam heap multi-generasi), maka ini sebenarnya dapat menyebabkan LEBIH BANYAK siklus cpu yang dikonsumsi daripada yang diperlukan.Dalam beberapa kasus, mungkin masuk akal untuk menyarankan VM agar melakukan pengumpulan penuh SEKARANG karena Anda mungkin tahu bahwa aplikasi akan menganggur selama beberapa menit ke depan sebelum pengangkatan berat terjadi. Misalnya, tepat setelah inisialisasi banyak objek sementara selama startup aplikasi (yaitu, saya baru saja menyimpan banyak info dalam cache, dan saya tahu saya tidak akan mendapatkan banyak aktivitas selama satu menit atau lebih). Pikirkan IDE seperti memulai gerhana - ia melakukan banyak hal untuk diinisialisasi, jadi mungkin segera setelah inisialisasi, masuk akal untuk melakukan gc penuh pada saat itu.
sumber
Anda harus sangat berhati-hati jika menelepon
System.gc()
. Memanggilnya dapat menambah masalah kinerja yang tidak perlu ke aplikasi Anda, dan tidak ada jaminan untuk benar-benar melakukan pengumpulan. Sebenarnya mungkin untuk menonaktifkan eksplisitSystem.gc()
melalui argumen java-XX:+DisableExplicitGC
.Saya sangat merekomendasikan membaca dokumen yang tersedia di Pengumpulan Sampah HotSpot Java untuk detail lebih mendalam tentang pengumpulan sampah.
sumber
System.gc()
diterapkan oleh VM, dan yang dilakukannya adalah spesifik penerapannya. Pelaksana dapat dengan mudah kembali dan tidak melakukan apa-apa, misalnya.Mengenai kapan harus mengeluarkan koleksi manual, satu-satunya saat Anda mungkin ingin melakukannya adalah ketika Anda meninggalkan koleksi besar yang berisi banyak koleksi yang lebih kecil -
Map<String,<LinkedList>>
misalnya - dan Anda ingin mencoba dan mengambil hasil kinerja saat itu dan di sana, tetapi untuk sebagian besar, Anda tidak perlu khawatir tentang itu. GC lebih tahu dari Anda - sayangnya - sebagian besar waktu.sumber
Jika Anda menggunakan buffer memori langsung, JVM tidak menjalankan GC untuk Anda meskipun memori langsung Anda hampir habis.
Jika Anda memanggil
ByteBuffer.allocateDirect()
dan Anda mendapatkan OutOfMemoryError Anda dapat menemukan panggilan ini baik-baik saja setelah memicu GC secara manual.sumber
Cleaners
yang digunakan memori langsung. yaitu tidak dibebaskan oleh utas finaliser karena ini bisa terlalu lambat. Meskipun demikian, OOME dapat diperoleh jika Anda membuat region memori langsung dengan sangat cepat. Solusinya adalah tidak melakukan itu dan menggunakan kembali wilayah memori langsung Anda di mana Anda bisa.Kebanyakan JVM akan memulai GC (bergantung pada sakelar -XX: DiableExplicitGC dan -XX: + ExplicitGCInvokesConcurrent). Tetapi spesifikasinya kurang didefinisikan dengan baik untuk memungkinkan implementasi yang lebih baik di kemudian hari.
Spesifikasi membutuhkan klarifikasi: Bug # 6668279: (spec) System.gc () harus menunjukkan bahwa kami tidak merekomendasikan penggunaan dan tidak menjamin perilaku
Secara internal, metode gc digunakan oleh RMI dan NIO, dan mereka membutuhkan eksekusi sinkron, yang: saat ini sedang dibahas:
Bug # 5025281: Izinkan System.gc () untuk memicu koleksi lengkap serentak (bukan stop-the-world)
sumber
Garbage Collection
bagusJava
, jika kita menjalankan Software yang dikodekan di java di Desktop / laptop / server. Anda dapat meneleponSystem.gc()
atauRuntime.getRuntime().gc()
masukJava
.Perhatikan bahwa tidak satu pun dari panggilan tersebut dijamin untuk melakukan apa pun. Itu hanya saran bagi jvm untuk menjalankan Pengumpul Sampah. Terserah JVM apakah itu menjalankan GC atau tidak. Jadi, jawaban singkatnya: kami tidak tahu kapan itu berjalan. Jawaban yang lebih panjang: JVM akan menjalankan gc jika ada waktu untuk itu.
Saya yakin, hal yang sama berlaku untuk Android. Namun, ini mungkin memperlambat sistem Anda.
sumber
Biasanya, VM akan melakukan pengumpulan sampah secara otomatis sebelum melontarkan OutOfMemoryException, jadi menambahkan panggilan eksplisit seharusnya tidak membantu kecuali karena hal itu mungkin memindahkan klik kinerja ke momen waktu yang lebih awal.
Namun, saya rasa saya menemukan kasus yang mungkin relevan. Saya tidak yakin, karena saya belum menguji apakah itu berpengaruh:
Saat Anda memetakan memori file, saya yakin panggilan map () melontarkan IOException saat blok memori yang cukup besar tidak tersedia. Pengumpulan sampah sebelum file map () mungkin membantu mencegahnya, saya kira. Bagaimana menurut anda?
sumber
kami tidak pernah bisa memaksa pengumpulan sampah. System.gc hanya menyarankan vm untuk pengumpulan sampah, namun sebenarnya jam berapa mekanisme tersebut berjalan, tidak ada yang tahu, ini seperti yang dinyatakan oleh spesifikasi JSR.
sumber
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 mengerjakan proyek yang melibatkan lingkungan terbatas memori dan jumlah data yang relatif besar - ada beberapa bagian besar data yang mendorong lingkungan saya ke batasnya, dan meskipun saya dapat menurunkan penggunaan memori begitu bahwa secara teori seharusnya berfungsi dengan baik, saya masih akan mendapatkan error ruang heap --- opsi GC yang bertele-tele menunjukkan kepada saya bahwa ia mencoba mengumpulkan sampah, tetapi tidak berhasil. Dalam debugger, saya dapat menjalankan System.gc () dan cukup yakin akan ada "banyak" memori yang tersedia ... tidak banyak tambahan, tetapi cukup.
Akibatnya, satu-satunya saat aplikasi saya memanggil System.gc () adalah ketika akan memasuki segmen kode di mana buffer besar yang diperlukan untuk memproses data akan dialokasikan, dan pengujian 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 berukuran 100-200 MB pada sumber. Itu semua adalah bagian dari proses konversi data otomatis, jadi semua data ada untuk jangka waktu yang relatif singkat dalam jangka panjang.
Sayangnya, meskipun informasi tentang berbagai opsi untuk menyetel pengumpul sampah tersedia, tampaknya sebagian besar merupakan proses eksperimental dan tingkat spesifik yang lebih rendah diperlukan untuk memahami cara 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 mengatasi batu sandungan yang ditimbulkan dengan bekerja dengan blok data yang lebih besar. Karena itu, System.gc () adalah alat .... alat yang sangat tidak dapat diandalkan, dan jika Anda tidak berhati-hati dengan cara menggunakannya, Anda akan berharap alat itu tidak berfungsi lebih sering daripada tidak.
sumber
Jika Anda ingin tahu apakah file
System.gc()
dipanggil, Anda dapat dengan Java 7 update 4 baru mendapatkan pemberitahuan ketika JVM melakukan Pengumpulan Sampah.Saya tidak 100% yakin bahwa kelas GarbageCollectorMXBean telah diperkenalkan di Java 7 update 4, karena saya tidak dapat menemukannya di catatan rilis, tetapi saya menemukan informasinya di situs javaperformancetuning .com
sumber
Saya tidak dapat memikirkan contoh spesifik saat menjalankan GC eksplisit itu baik.
Secara umum, menjalankan GC eksplisit sebenarnya dapat menyebabkan lebih banyak kerugian daripada kebaikan, karena gc eksplisit akan memicu pengumpulan penuh, yang memakan waktu lebih lama secara signifikan saat melewati setiap objek. Jika gc eksplisit ini akhirnya dipanggil berulang kali, ini dapat dengan mudah menyebabkan aplikasi menjadi lambat karena banyak waktu yang dihabiskan untuk menjalankan GC penuh.
Alternatifnya, jika menelusuri heap dengan penganalisis heap dan Anda mencurigai komponen pustaka memanggil GC eksplisit, Anda dapat menonaktifkannya dengan menambahkan: gc = -XX: + DisableExplicitGC ke parameter JVM.
sumber
Berdasarkan Thinking in Java oleh Bruce Eckel, satu kasus penggunaan untuk panggilan System.gc () eksplisit adalah ketika Anda ingin memaksakan penyelesaian, yaitu panggilan untuk menyelesaikan metode.
sumber
sementara system.gc bekerja, itu akan menghentikan dunia: semua tanggapan dihentikan sehingga pengumpul sampah dapat memindai setiap objek untuk memeriksa apakah perlu dihapus. jika aplikasinya adalah proyek web, semua permintaan dihentikan hingga gc selesai, dan ini akan menyebabkan proyek web Anda tidak dapat bekerja dalam satu waktu.
sumber