Saran umum adalah Anda tidak boleh menelepon GC.Collect
dari kode Anda, tetapi apa pengecualian untuk aturan ini?
Saya hanya bisa memikirkan beberapa kasus yang sangat spesifik di mana mungkin masuk akal untuk memaksa pengumpulan sampah.
Salah satu contoh yang muncul dalam pikiran adalah layanan, yang bangun pada interval, melakukan beberapa tugas, dan kemudian tidur untuk waktu yang lama. Dalam hal ini, mungkin ide yang baik untuk memaksa pengumpulan untuk mencegah proses yang akan segera idle dari memegang lebih banyak memori daripada yang dibutuhkan.
Apakah ada kasus lain di mana panggilan dapat diterima GC.Collect
?
c#
.net
garbage-collection
Brian Rasmussen
sumber
sumber
Jawaban:
Jika Anda memiliki alasan kuat untuk meyakini bahwa serangkaian objek penting - terutama yang Anda duga berada pada generasi 1 dan 2 - sekarang memenuhi syarat untuk pengumpulan sampah, dan bahwa sekarang akan menjadi waktu yang tepat untuk mengumpulkan dalam hal hit kinerja kecil .
Contoh yang baik dari ini adalah jika Anda baru saja menutup formulir besar. Anda tahu bahwa semua kontrol UI sekarang dapat berupa sampah yang dikumpulkan, dan jeda yang sangat singkat karena formulir ditutup mungkin tidak akan terlihat oleh pengguna.
PEMBARUAN 2.7.2018
Pada. NET 4.5 - ada
GCLatencyMode.LowLatency
danGCLatencyMode.SustainedLowLatency
. Saat memasuki dan meninggalkan salah satu mode ini, Anda disarankan untuk memaksakan GC penuhGC.Collect(2, GCCollectionMode.Forced)
.Pada. NET 4.6 - ada
GC.TryStartNoGCRegion
metode (digunakan untuk mengatur nilai read-onlyGCLatencyMode.NoGCRegion
). Ini dapat dengan sendirinya, melakukan pengumpulan sampah penuh dalam upaya untuk membebaskan memori yang cukup, tetapi mengingat kita melarang GC untuk suatu periode, saya berpendapat itu juga merupakan ide yang baik untuk melakukan GC penuh sebelum dan sesudah.Sumber: Insinyur Microsoft Ben Watson: Menulis .NET Code Berkinerja Tinggi , 2nd Ed. 2018.
Lihat:
sumber
GC.Collect
Anda tampilkan ) memenuhi syarat untuk pengumpulan sampah - jadi dengan menelepon Anda pada dasarnya memberitahu pengumpul sampah yang Anda kenal lebih baik daripada untuk perubahan. Mengapa Anda tidak menyukai contohnya?GC.Collect()
akan meminta GC melakukan pengumpulan penuh . Jika Anda tahu bahwa Anda baru saja membuat banyak objek yang berumur panjang sebelumnya yang memenuhi syarat untuk pengumpulan sampah dan Anda yakin pengguna cenderung melihat sedikit jeda sekarang daripada nanti, tampaknya sepenuhnya masuk akal untuk berpikir bahwa sekarang lebih baik waktu untuk meminta koleksi daripada membiarkannya terjadi nanti.Saya
GC.Collect
hanya menggunakan saat menulis rig uji kinerja / profiler kasar; yaitu saya memiliki dua (atau lebih) blok kode untuk diuji - sesuatu seperti:Jadi itu
TestA()
danTestB()
jalankan dengan kondisi yang sama mungkin - yaituTestB()
tidak mendapatkan palu hanya karenaTestA
meninggalkannya sangat dekat dengan titik kritis.Contoh klasik akan menjadi konsol exe sederhana (
Main
metode sort-cukup untuk diposting di sini misalnya), yang menunjukkan perbedaan antara penggabungan string melingkar danStringBuilder
.Jika saya membutuhkan sesuatu yang tepat, maka ini akan menjadi dua tes yang sepenuhnya independen - tetapi seringkali ini cukup jika kita hanya ingin meminimalkan (atau menormalkan) GC selama tes untuk mendapatkan kesan kasar terhadap perilaku tersebut.
Selama kode produksi? Saya belum menggunakannya ;-p
sumber
Praktik terbaik adalah tidak memaksa pengumpulan sampah dalam banyak kasus. (Setiap sistem yang saya kerjakan yang memiliki pengumpulan sampah paksa, menggarisbawahi masalah yang jika diselesaikan akan menghilangkan kebutuhan untuk memaksa pengumpulan sampah, dan mempercepat sistem dengan sangat cepat.)
Ada beberapa kasus ketika Anda tahu lebih banyak tentang penggunaan memori maka pengumpul sampah tidak. Ini tidak mungkin benar dalam aplikasi multi-pengguna, atau layanan yang merespons lebih dari satu permintaan sekaligus.
Namun dalam beberapa jenis pemrosesan batch Anda tahu lebih banyak daripada GC. Misalnya pertimbangkan aplikasi itu.
Anda mungkin dapat membuat case (setelah hati-hati) menguji bahwa Anda harus memaksa pengumpulan sampah penuh setelah Anda memproses setiap file.
Kasing lain adalah layanan yang bangun setiap beberapa menit untuk memproses beberapa barang, dan tidak membuat keadaan apa pun saat tertidur . Maka, memaksakan koleksi penuh sebelum tidur mungkin bermanfaat.
Saya lebih suka memiliki API pengumpulan sampah ketika saya bisa memberikan petunjuk tentang hal semacam ini tanpa harus memaksakan GC diri saya.
Lihat juga " Tidbits Kinerja Rico Mariani "
sumber
Satu kasus adalah ketika Anda mencoba untuk menyatukan kode uji yang menggunakan WeakReference .
sumber
Dalam sistem besar 24/7 atau 24/6 - sistem yang bereaksi terhadap pesan, permintaan RPC atau yang polling database atau proses terus menerus - hal ini berguna untuk memiliki cara untuk mengidentifikasi kebocoran memori. Untuk ini, saya cenderung menambahkan mekanisme ke aplikasi untuk menangguhkan sementara pemrosesan dan kemudian melakukan pengumpulan sampah penuh. Ini menempatkan sistem ke keadaan diam di mana memori yang tersisa adalah memori yang berumur panjang secara sah (cache, konfigurasi, & c.) Atau yang lain 'bocor' (objek yang tidak diharapkan atau diinginkan untuk di-root tetapi sebenarnya).
Memiliki mekanisme ini memudahkan penggunaan memori profil karena laporan tidak akan disurvei dengan noise dari pemrosesan aktif.
Untuk memastikan Anda mendapatkan semua sampah, Anda perlu melakukan dua koleksi:
Karena koleksi pertama akan menyebabkan objek dengan finalizer diselesaikan (tetapi sebenarnya sampah tidak mengumpulkan objek-objek ini). GC kedua akan mengumpulkan sampah benda-benda yang diselesaikan ini.
sumber
Anda dapat menghubungi GC.Collect () ketika Anda tahu sesuatu tentang sifat aplikasi yang tidak dimiliki oleh pemulung. Sangat menggoda untuk berpikir bahwa, sebagai penulis, ini sangat mungkin. Namun, kebenarannya adalah jumlah GC untuk sistem pakar yang cukup baik ditulis dan diuji, dan jarang Anda akan tahu sesuatu tentang jalur kode tingkat rendah yang tidak.
Contoh terbaik yang dapat saya pikirkan di mana Anda mungkin memiliki beberapa informasi tambahan adalah aplikasi yang siklus antara periode idle dan periode yang sangat sibuk. Anda ingin kinerja terbaik untuk periode sibuk dan karena itu ingin menggunakan waktu siaga untuk melakukan pembersihan.
Namun, sebagian besar waktu GC cukup pintar untuk melakukan ini.
sumber
Sebagai solusi fragmentasi memori. Saya keluar dari pengecualian memori saat menulis banyak data ke dalam aliran memori (membaca dari aliran jaringan). Data ditulis dalam potongan 8K. Setelah mencapai 128M ada pengecualian meskipun ada banyak memori yang tersedia (tetapi terfragmentasi). Memanggil GC.Collect () menyelesaikan masalah. Saya dapat menangani lebih dari 1G setelah perbaikan.
sumber
Lihat artikel ini oleh Rico Mariani. Dia memberikan dua aturan kapan harus menelepon GC.Collect (aturan 1 adalah: "Jangan"):
Kapan menelepon GC.Collect ()
sumber
Salah satu contoh di mana hampir perlu untuk memanggil GC.Collect () adalah ketika mengotomatisasi Microsoft Office melalui Interop. Objek COM untuk Office tidak suka dilepaskan secara otomatis dan dapat mengakibatkan instance produk Office menghabiskan banyak memori. Saya tidak yakin apakah ini masalah atau karena desain. Ada banyak posting tentang topik ini di internet jadi saya tidak akan membahas terlalu banyak detail.
Saat pemrograman menggunakan Interop, setiap objek COM tunggal harus dirilis secara manual, biasanya melalui penggunaan Marshal.ReleseComObject (). Selain itu, memanggil Pengumpulan Sampah secara manual dapat membantu "membersihkan" sedikit. Memanggil kode berikut ketika Anda selesai dengan objek Interop tampaknya cukup membantu:
Dalam pengalaman pribadi saya, menggunakan kombinasi ReleaseComObject dan pengumpulan sampah secara manual sangat mengurangi penggunaan memori produk Office, khususnya Excel.
sumber
Saya sedang melakukan beberapa pengujian kinerja pada array dan daftar:
dan saya
OutOfMemoryException
menggunakan metode GetSomeNumbers_Enumerable_Range satu-satunya solusi adalah dengan mendeallocate memori dengan:sumber
Dalam contoh Anda, saya berpikir bahwa memanggil GC.Collect bukan masalah, tetapi ada masalah desain.
Jika Anda akan bangun secara berkala, (atur waktu) maka program Anda harus dibuat untuk satu eksekusi (melakukan tugas sekali) dan kemudian berakhir. Kemudian, Anda mengatur program sebagai tugas yang dijadwalkan untuk dijalankan pada interval yang dijadwalkan.
Dengan cara ini, Anda tidak perlu khawatir dengan menelepon GC.Collect, (yang harus Anda jarang lakukan).
Yang sedang berkata, Rico Mariani memiliki posting blog yang bagus tentang hal ini, yang dapat ditemukan di sini:
http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
sumber
Satu tempat yang berguna untuk memanggil GC.Collect () adalah dalam unit test ketika Anda ingin memverifikasi bahwa Anda tidak membuat kebocoran memori (misalnya jika Anda melakukan sesuatu dengan Referensi Lemah atau ConditionalWeakTable, kode yang dihasilkan secara dinamis, dll).
Sebagai contoh, saya punya beberapa tes seperti:
Dapat diperdebatkan bahwa menggunakan WeakReferences adalah masalah dalam dirinya sendiri, tetapi tampaknya jika Anda membuat sistem yang bergantung pada perilaku seperti itu maka memanggil GC.Collect () adalah cara yang baik untuk memverifikasi kode tersebut.
sumber
Entri blog Scott Holden tentang kapan harus (dan kapan tidak) memanggil GC.Collect khusus untuk .NET Compact Framework , tetapi aturan umumnya berlaku untuk semua pengembangan yang dikelola.
sumber
Jawaban singkatnya adalah: tidak pernah!
sumber
sumber
Ada beberapa situasi di mana itu lebih aman daripada menyesal.
Inilah satu situasi.
Dimungkinkan untuk membuat DLL yang tidak dikelola di C # menggunakan penulisan ulang IL (karena ada situasi di mana ini diperlukan).
Sekarang misalkan, misalnya, DLL membuat array byte di tingkat kelas - karena banyak fungsi yang diekspor memerlukan akses ke sana. Apa yang terjadi ketika DLL dibongkar? Apakah pemungut sampah secara otomatis dipanggil pada saat itu? Saya tidak tahu, tetapi sebagai DLL yang tidak dikelola , sangat mungkin GC tidak dipanggil. Dan itu akan menjadi masalah besar jika tidak dipanggil. Ketika DLL dibongkar juga akan menjadi pengumpul sampah - jadi siapa yang akan bertanggung jawab untuk mengumpulkan sampah yang mungkin dan bagaimana mereka melakukannya? Lebih baik mempekerjakan pengumpul sampah C #. Memiliki fungsi pembersihan (tersedia untuk klien DLL) di mana variabel tingkat kelas diatur ke nol dan pemulung disebut.
Lebih baik aman daripada menyesal.
sumber
saya masih sangat tidak yakin tentang ini. Saya bekerja sejak 7 tahun di Server Aplikasi. Instalasi kami yang lebih besar menggunakan Ram 24 GB. Multithreaded, dan SEMUA panggilan untuk GC.Collect () mengalami masalah kinerja yang sangat mengerikan.
Banyak Komponen pihak ketiga menggunakan GC.Collect () ketika mereka pikir itu pintar untuk melakukan ini sekarang. Jadi sekelompok sederhana Excel-Report memblokir App Server untuk semua utas beberapa kali dalam satu menit.
Kami harus memperbaiki semua Komponen Pihak ke-3 untuk menghapus panggilan GC.Collect (), dan semua bekerja dengan baik setelah melakukan ini.
Tetapi saya menjalankan Server di Win32 juga, dan di sini saya mulai menggunakan GC.Collect () setelah mendapatkan OutOfMemoryException.
Tetapi saya juga tidak yakin tentang hal ini, karena saya sering memperhatikan, ketika saya mendapatkan OOM pada 32 Bit, dan saya coba lagi untuk menjalankan Operasi yang sama lagi, tanpa memanggil GC.Collect (), itu hanya berfungsi dengan baik.
Satu hal yang saya heran adalah Pengecualian OOM itu sendiri ... Jika saya akan menulis .Net Framework, dan saya tidak dapat mengalokasikan blok memori, saya akan menggunakan GC.Collect (), defrag memory (??), coba lagi , dan jika saya masih tidak dapat menemukan blok memori gratis, maka saya akan membuang OOM-Exception.
Atau setidaknya menjadikan perilaku ini sebagai opsi yang dapat dikonfigurasi, karena kelemahan masalah kinerja dengan GC.Collect.
Sekarang saya punya banyak kode seperti ini di aplikasi saya untuk "menyelesaikan" masalah:
(Perhatikan bahwa perilaku Thread.Sleep () adalah perilaku yang benar-benar spesifik untuk aplikasi, karena kami menjalankan Layanan Caching ORM, dan layanan ini membutuhkan waktu untuk melepaskan semua objek yang di-cache, jika RAM melebihi beberapa nilai yang telah ditentukan. Jadi ia menunggu beberapa detik pertama kalinya, dan telah meningkatkan waktu tunggu setiap kemunculan OOM.)
sumber
GC.Collect
. Karena memiliki efek lebar aplikasi hanya aplikasi yang seharusnya melakukannya (jika ada).If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(),
- Saya pikir mereka sudah melakukan ini - Saya telah melihat indikasi bahwa salah satu pemicu GC internal adalah kegagalan tertentu untuk mengalokasikan memori.Anda harus mencoba untuk menghindari menggunakan GC.Collect () karena sangat mahal. Berikut ini sebuah contoh:
HASIL UJI: PENGGUNAAN CPU 12%
Ketika Anda mengubah ini:
HASIL UJI: PENGGUNAAN CPU 2-3%
sumber
Alasan lain adalah ketika Anda memiliki SerialPort dibuka pada port USB COM, dan kemudian perangkat USB dicabut. Karena SerialPort dibuka, sumber daya memegang referensi ke port yang sebelumnya terhubung dalam registri sistem. Registri sistem kemudian akan berisi data basi , sehingga daftar port yang tersedia akan salah. Karena itu pelabuhan harus ditutup.
Memanggil SerialPort.Close () pada panggilan port Buang () pada objek, tetapi tetap dalam memori sampai pengumpulan sampah benar-benar berjalan, menyebabkan registri tetap basi sampai pengumpul sampah memutuskan untuk melepaskan sumber daya.
Dari https://stackoverflow.com/a/58810699/8685342 :
sumber
Ini tidak relevan dengan pertanyaan, tetapi untuk transformasi XSLT di .NET (XSLCompiledTranform) maka Anda mungkin tidak punya pilihan. Kandidat lain adalah kontrol MSHTML.
sumber
Jika Anda menggunakan versi .net kurang dari 4,5, koleksi manual mungkin tidak terhindarkan (terutama jika Anda berurusan dengan banyak 'objek besar').
tautan ini menjelaskan alasannya:
https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/
sumber
satu alasan bagus untuk memanggil GC adalah pada komputer ARM kecil dengan memori sedikit, seperti Raspberry PI (berjalan dengan mono). Jika fragmen memori yang tidak terisi menggunakan terlalu banyak RAM sistem, maka OS Linux bisa menjadi tidak stabil. Saya memiliki aplikasi di mana saya harus memanggil GC setiap detik (!) Untuk menyingkirkan masalah memori yang berlebihan.
Solusi lain yang baik adalah membuang benda ketika tidak lagi dibutuhkan. Sayangnya ini tidak mudah dalam banyak kasus.
sumber
Karena ada tumpukan objek kecil (SOH) dan tumpukan objek besar (LOH)
Kita dapat memanggil GC.Collect () untuk menghapus objek de-referensi di SOP, dan memindahkan objek hidup ke generasi berikutnya.
Di .net4.5, kita juga bisa memadatkan LOH dengan menggunakan metode objek besar
sumber
Jika Anda membuat banyak
System.Drawing.Bitmap
objek baru , Pengumpul Sampah tidak membersihkannya. Akhirnya GDI + akan berpikir Anda kehabisan memori dan akan mengeluarkan pengecualian "Parameter tidak valid". MeneleponGC.Collect()
sesering mungkin (tidak terlalu sering!) Sepertinya bisa mengatasi masalah ini.sumber