Apa salahnya menggunakan GC.Collect ()?

103

Meskipun saya benar-benar memahami implikasi serius dari bermain-main dengan fungsi ini (atau setidaknya itulah yang saya pikirkan), saya gagal untuk memahami mengapa itu menjadi salah satu hal yang tidak akan pernah digunakan oleh programmer terhormat, bahkan mereka yang bahkan tidak tahu. untuk apa ini.

Katakanlah saya sedang mengembangkan aplikasi di mana penggunaan memori sangat bervariasi tergantung pada apa yang dilakukan pengguna. Siklus hidup aplikasi dapat dibagi menjadi dua tahap utama: pengeditan dan pemrosesan waktu nyata. Selama tahap pengeditan, anggaplah miliaran atau bahkan triliunan objek tercipta; beberapa dari mereka kecil dan beberapa tidak, beberapa mungkin memiliki finalizer dan beberapa mungkin tidak, dan anggap masa hidup mereka bervariasi dari beberapa milidetik hingga berjam-jam. Selanjutnya, pengguna memutuskan untuk beralih ke tahap waktu nyata. Pada titik ini, anggaplah bahwa kinerja memainkan peran fundamental dan perubahan sekecil apa pun dalam aliran program dapat membawa konsekuensi bencana. Pembuatan objek kemudian dikurangi seminimal mungkin dengan menggunakan kumpulan objek dan semacamnya tetapi kemudian, GC berbunyi secara tak terduga dan membuang semuanya, dan seseorang mati.

Pertanyaannya: Dalam hal ini, bukankah bijaksana untuk memanggil GC.Collect () sebelum memasuki tahap kedua?

Bagaimanapun, kedua tahap ini tidak pernah tumpang tindih dalam waktu satu sama lain dan semua pengoptimalan dan statistik yang bisa dikumpulkan oleh GC akan sedikit berguna di sini ...

Catatan: Seperti yang telah Anda tunjukkan, .NET mungkin bukan platform terbaik untuk aplikasi seperti ini, tetapi itu di luar cakupan pertanyaan ini. Tujuannya adalah untuk memperjelas apakah panggilan GC.Collect () bisa meningkatkan perilaku / kinerja aplikasi secara keseluruhan atau tidak. Kita semua setuju bahwa keadaan di mana Anda akan melakukan hal seperti itu sangat jarang, tetapi sekali lagi, GC mencoba untuk menebak dan melakukannya dengan sangat baik hampir sepanjang waktu, tetapi ini masih tentang menebak.

Terima kasih.

Trap
sumber
24
"perubahan sekecil apa pun dalam aliran program dapat membawa konsekuensi bencana ... seseorang dapat meninggal" - apakah Anda yakin C # .NET cukup deterministik untuk tujuan Anda?
Steve Jessop
4
Bukan Windows atau .NET yang merupakan platform waktu nyata dan oleh karena itu Anda tidak dapat menjamin metrik kinerja, setidaknya tidak cukup sampai membahayakan nyawa manusia. Saya setuju dengan satu orang bahwa Anda melebih-lebihkan atau ceroboh.
Sergio Acosta
3
LOL pada "salah satu dari hal-hal ini yang tidak akan pernah digunakan oleh programmer terhormat, bahkan mereka yang bahkan tidak tahu untuk apa"! Programmer yang menggunakan hal-hal yang tidak tahu mengapa hampir tidak dianggap paling terhormat dalam buku saya. :)
The Dag

Jawaban:

87

Dari Blog Rico ...

Aturan # 1

Jangan.

Ini benar-benar aturan yang paling penting. Cukup adil untuk mengatakan bahwa sebagian besar penggunaan GC.Collect () adalah ide yang buruk dan saya membahasnya secara mendetail di postingan asli jadi saya tidak akan mengulangi semua itu di sini. Jadi mari kita lanjutkan ke ...

Aturan # 2

Pertimbangkan untuk memanggil GC.Collect () jika beberapa peristiwa tidak berulang baru saja terjadi dan peristiwa ini kemungkinan besar telah menyebabkan banyak objek lama mati.

Contoh klasik dari ini adalah jika Anda sedang menulis aplikasi klien dan Anda menampilkan formulir yang sangat besar dan rumit yang memiliki banyak data yang terkait dengannya. Pengguna Anda baru saja berinteraksi dengan formulir ini berpotensi membuat beberapa objek besar ... hal-hal seperti dokumen XML, atau Kumpulan Data besar atau dua. Ketika formulir menutup, objek-objek ini mati dan GC.Collect () akan mengambil kembali memori yang terkait dengannya ...

Jadi sepertinya situasi ini mungkin termasuk dalam Aturan # 2, Anda tahu bahwa ada saat di mana banyak benda tua telah mati, dan itu tidak berulang. Namun, jangan lupakan kata-kata perpisahan Rico.

Aturan # 1 harus mengalahkan Aturan # 2 tanpa bukti kuat.

Ukur, ukur, ukur.

Jon Norton
sumber
9
Saya akan mengatakan ini hanya hal yang lama. Tidak ada yang benar-benar buruk atau berbahaya jika Anda tahu apa yang Anda lakukan dan karena itu tahu kapan dan bagaimana melakukannya, serta efek sampingnya. Hal-hal seperti jangan pernah, pernah menggunakan xxxx ditempatkan di sana untuk melindungi dunia dari programmer yang buruk: D
Jorge Córdoba
lihat juga stackoverflow.com/questions/233596/…
Ian Ringrose
Saya tidak mengatakan menggunakan GC. Collect adalah praktik yang baik. Tetapi terkadang ini adalah cara cepat untuk menyelesaikan masalah tanpa mengetahui penyebab sebenarnya. Itu jelek, saya tahu, tapi itu berhasil, dan menurut saya itu bukan pendekatan yang buruk, terutama ketika tidak ada banyak waktu untuk mencari tahu akar penyebab masalah dan bos Anda berdiri di belakang Anda ... Anda tahu.
Silent Sojourner
58

Jika Anda memanggil GC.Collect () dalam kode produksi, pada dasarnya Anda menyatakan bahwa Anda mengetahui lebih banyak daripada penulis GC. Mungkin itu masalahnya. Namun biasanya tidak, dan oleh karena itu sangat tidak disarankan.

Aaron Fischer
sumber
3
Itu sangat benar, tapi saya tidak tahu apakah mereka bisa membuat asumsi yang berlaku untuk semua perkembangan.
MasterMastic
2
@Ken Tidak, mereka tidak bisa. Tetapi apakah Anda dalam posisi yang lebih baik untuk melakukannya? Atau apakah Anda akan menulis kode dengan asumsi perangkat keras tertentu, versi OS tertentu, dan sebagainya? Rasio nyeri / keuntungan terlalu tinggi untuk yang satu ini.
The Dag
2
@TheDag IMO tentu saja saya. Ketika saya melepaskan memori dan yang lainnya, saya tidak terlalu peduli dengan perangkat keras karena itulah tugas OS untuk mengatasinya. Saya juga tidak peduli tentang OS karena saya memiliki antarmuka yang umum untuk semua yang saya pemrograman. (misalnya saya tidak peduli apakah itu Windows, Mac, atau Linux: ketika saya mengalokasikan / mengosongkan memori di C / C ++ ini baru / hapus malloc / dealloc). Saya selalu bisa salah jadi jangan ragu untuk mengoreksi saya.
MasterMastic
@MasterMastic mallochanya memiliki antarmuka yang sangat sederhana, dan implementasinya dapat cukup bervariasi. Itu semua tergantung pada jenis masalah yang Anda coba selesaikan. Jika malloc"cukup baik", Anda tidak perlu buffer pooling, bukan? Pengembangan C / C ++ penuh dengan contoh di mana Anda mencoba menebak-nebak OS / runtime / libraries karena Anda lebih tahu (dan terkadang, Anda benar-benar tahu). Banyak aplikasi yang mengutamakan kinerja menghindari penggunaan pengalokasi sistem / waktu proses sepenuhnya. Game yang digunakan untuk mengalokasikan semua memori saat startup (array berukuran konstan, dll.).
Luaan
24

Jadi bagaimana jika Anda menggunakan objek COM seperti MS Word atau MS Excel dari .NET? Tanpa memanggil GC.Collectsetelah melepaskan objek COM kami telah menemukan bahwa contoh aplikasi Word atau Excel masih ada.

Sebenarnya kode yang kami gunakan adalah:

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

Jadi, apakah itu penggunaan pengumpul sampah yang salah? Jika demikian, bagaimana kita membuat objek Interop mati? Juga jika tidak dimaksudkan untuk digunakan seperti ini, mengapa adalah GC's Collectmetode bahkan Public?

Dib
sumber
3
Ini akan menjadi pertanyaan StackOverflow baru yang hebat, yaitu: Bagaimana menghapus instance COM tanpa memanggil GC. Berkenaan dengan referensi melingkar yang tidak terkelola. Itu salah satu tantangan yang membuat saya waspada dalam memutakhirkan add-in Outlook VB6 saya ke C #. (Kami melakukan banyak pekerjaan untuk mengembangkan pola pengkodean dan menguji kasus di sisi VB yang menjamin referensi COM dibunuh secara deterministik ketika tidak lagi diperlukan).
rkagerer
2
Jika ini berlaku untuk objek COM secara umum, mungkin ini adalah skenario yang valid. Tapi dari kelelawar saya akan mengatakan masalahnya kemungkinan bahwa Anda menggunakan aplikasi klien yang dirancang untuk desktop interaktif sebagai server COM. Dari basis pengetahuan MSDN: "Microsoft saat ini tidak merekomendasikan, dan tidak mendukung, Otomatisasi aplikasi Microsoft Office dari setiap aplikasi klien non-interaktif atau komponen yang tidak dijaga (termasuk ASP, ASP.NET, DCOM, dan Layanan NT), karena Office mungkin menunjukkan perilaku yang tidak stabil dan / atau kebuntuan saat Office dijalankan di lingkungan ini. "
The Dag
2
@TheDag - Microsoft mungkin tidak merekomendasikan, tetapi banyak dari kita harus mem-port kode VB6 lama dengan interop kantor ke aplikasi Windows .Net. Saya menghabiskan waktu berbulan-bulan bekerja sampai akhirnya saya menyingkirkan semua referensi gantung yang tidak terlihat untuk proyek konversi VB6 menjadi .Net yang besar. Belajar melepaskan dalam urutan tugas terbalik dan menahan referensi lokal ke SETIAP objek com tunggal termasuk koleksi membantu.
Dib
15

Nah, GC adalah salah satu hal yang memiliki hubungan cinta / benci dengan saya. Kami telah memecahkannya di masa lalu melalui VistaDB dan membuat blog tentangnya. Mereka telah memperbaikinya, tetapi butuh waktu lama untuk mendapatkan perbaikan dari mereka untuk hal-hal seperti ini.

GC itu rumit, dan pendekatan satu ukuran untuk semua sangat, sangat sulit untuk dilakukan pada sesuatu yang sebesar ini. MS telah melakukan tugasnya dengan cukup baik, tetapi terkadang ada kemungkinan untuk menipu GC.

Secara umum, Anda tidak boleh menambahkan a Collectkecuali Anda tahu pasti bahwa Anda baru saja membuang banyak memori dan itu akan menuju krisis paruh baya jika GC tidak membersihkannya sekarang.

Anda dapat mengacaukan seluruh mesin dengan serangkaian GC.Collectpernyataan buruk . Kebutuhan akan pernyataan kumpulkan hampir selalu menunjuk pada kesalahan mendasar yang lebih besar. Kebocoran memori biasanya berkaitan dengan referensi dan kurangnya pemahaman tentang cara kerjanya. Atau penggunaan fileIDisposable on object yang tidak membutuhkannya dan meletakkan beban yang jauh lebih tinggi pada GC.

Perhatikan dengan cermat% waktu yang dihabiskan di GC melalui penghitung kinerja sistem. Jika Anda melihat aplikasi Anda menggunakan 20% atau lebih waktunya di GC, Anda memiliki masalah pengelolaan objek yang serius (atau pola penggunaan yang tidak normal). Anda ingin selalu meminimalkan waktu yang dihabiskan GC karena ini akan mempercepat seluruh aplikasi Anda.

Penting juga untuk dicatat bahwa GC di server berbeda dengan workstation. Saya telah melihat sejumlah masalah kecil yang sulit dilacak dengan orang-orang yang tidak menguji keduanya (atau bahkan tidak menyadari bahwa mereka adalah keduanya).

Dan agar jawaban saya selengkap mungkin, Anda juga harus menguji di bawah Mono jika Anda menargetkan platform itu juga. Karena ini adalah implementasi yang sangat berbeda, itu mungkin mengalami masalah yang sama sekali berbeda dari implementasi MS.

Jason Short
sumber
Pelakunya sering kali adalah peristiwa. Setiap kali metode instance digunakan sebagai pengendali kejadian, penerbit acara memiliki referensi ke pelanggan melalui delegasi acara. Satu-satunya cara "mudah" untuk menghindari masalah dari ini adalah dengan hanya menggunakan penerbit yang berumur paling lama sebagai pelanggan (misalnya TextBox menerbitkan acara yang ditangani oleh formulir yang berisi tidak masalah, karena kotak teks tidak seharusnya untuk hidup di luar bentuk). Contoh skenario masalah: Model tunggal, tampilan sementara menangani peristiwa model.
The Dag
5
Bagaimana seseorang bisa mengacaukan seluruh mesin?
Adam
13

Ada situasi di mana itu berguna, tetapi secara umum itu harus dihindari. Anda dapat membandingkannya dengan GOTO, atau mengendarai moped: Anda melakukannya saat diperlukan, tetapi Anda tidak memberi tahu teman Anda tentang hal itu.

rjohnston
sumber
12

Dari pengalaman saya, tidak pernah disarankan untuk melakukan panggilan ke GC.Collect () dalam kode produksi. Dalam debugging, ya, ada keuntungannya untuk membantu mengklarifikasi potensi kebocoran memori. Saya kira alasan mendasar saya adalah bahwa GC telah ditulis dan dioptimalkan oleh programmer jauh lebih pintar daripada saya, dan jika saya sampai pada suatu titik di mana saya merasa perlu memanggil GC.Collect () itu adalah petunjuk bahwa saya telah keluar jalur di suatu tempat. Dalam situasi Anda, sepertinya Anda tidak benar-benar memiliki masalah memori, hanya saja Anda khawatir tentang ketidakstabilan apa yang akan dibawa oleh koleksi ke proses Anda. Melihat bahwa itu tidak akan membersihkan objek yang masih digunakan, dan menyesuaikan dengan sangat cepat baik untuk naik maupun turunnya permintaan, saya rasa Anda tidak perlu mengkhawatirkannya.

TheZenker
sumber
10

Salah satu alasan terbesar untuk memanggil GC.Collect () adalah saat Anda baru saja melakukan peristiwa penting yang menghasilkan banyak sampah, seperti yang Anda gambarkan. Memanggil GC.Collect () bisa menjadi ide bagus di sini; jika tidak, GC mungkin tidak memahami bahwa ini adalah peristiwa 'satu kali'.

Tentu saja, Anda harus membuat profil, dan melihat sendiri.

TraumaPony
sumber
9

Nah, jelas Anda tidak boleh menulis kode dengan persyaratan waktu nyata dalam bahasa dengan pengumpulan sampah non-waktu nyata.

Dalam kasus dengan tahapan yang ditentukan dengan baik, tidak ada masalah dengan memicu pengumpul sampah. Tapi kasus ini sangat jarang terjadi. Masalahnya adalah bahwa banyak pengembang akan mencoba menggunakan ini untuk masalah kertas-over dengan gaya kultus kargo, dan menambahkannya tanpa pandang bulu akan menyebabkan masalah kinerja.

wnoise
sumber
Benar. Namun pengujian otomatis yang mampu menangkap kondisi kesalahan "objek tidak memenuhi syarat untuk pengumpulan sampah, tetapi harus" akan bermanfaat. I ini dapat dicapai melalui kombinasi logika pabrik, logika destruktor, dan GC.Collect. Misalnya kelas Entitas Anda memiliki properti IObjectTracker, biasanya null, tetapi ditetapkan oleh pabrik entitas tujuan pengujian. Pabrik juga memberi tahu pelacak kelahiran objek, sedangkan destruktor memberi tahu (jika ada) kematian. Jika Anda dapat mengetahui "destruktor telah dieksekusi untuk semua objek yang dapat dikoleksi sampah", Anda dapat memeriksa status pelacak untuk mendeteksi kebocoran.
The Dag
7

Memanggil GC.Collect () memaksa CLR melakukan stack walk untuk melihat apakah setiap objek benar-benar bisa dilepaskan dengan memeriksa referensi. Ini akan memengaruhi skalabilitas jika jumlah objeknya banyak, dan juga diketahui memicu pengumpulan sampah terlalu sering. Percayai CLR dan biarkan pengumpul sampah berjalan sendiri saat diperlukan.

Ta01
sumber
2
Anda tidak hanya menyebabkan stack walk, tetapi thread utama aplikasi Anda (dan semua thread turunan yang dibuatnya) dibekukan sehingga GC dapat menjalankan stack. Semakin banyak waktu yang dihabiskan aplikasi Anda di GC, semakin banyak waktu yang dihabiskan untuk membekukan.
Scott Dorman
3
Saya lebih khawatir tentang App Crash karena pengecualian Out of Memory daripada kinerja lambat karena app / GC membuang hal-hal yang tidak lagi diperlukan. Adakah yang tahu mengapa Microsoft tampaknya membuang pengecualian OOM tanpa terlebih dahulu membuang sampah? (Tanpa langkah JELAS ini - atau setidaknya penjelasan mengapa langkah ini tampaknya tidak dicoba sebelum mengeluarkan pengecualian OOM Saya tidak yakin saya memiliki keyakinan dalam hal-hal yang terjadi "secara otomatis" dengan "cara yang seharusnya."
Wonderbird
6

Faktanya, menurut saya bukan praktik yang sangat buruk untuk menelepon GC.Collect.
Mungkin ada kasus ketika kita membutuhkannya. Sebagai contoh, saya memiliki formulir yang menjalankan utas, yang kemudian membuka tabel berbeda dalam database, mengekstrak konten di bidang BLOB ke file temp, mengenkripsi file, lalu membaca file tersebut ke dalam binarystream dan kembali ke BLOB bidang di tabel lain.

Seluruh operasi membutuhkan banyak memori, dan tidak pasti tentang jumlah baris dan ukuran konten file dalam tabel.

Saya dulu sering mendapatkan OutofMemory Exception dan saya pikir akan bijaksana untuk menjalankan GC.Collect secara berkala berdasarkan variabel counter. Saya menambah penghitung dan ketika level tertentu tercapai, GC dipanggil untuk mengumpulkan sampah apa pun yang mungkin telah terbentuk, dan untuk mendapatkan kembali memori yang hilang karena kebocoran memori yang tidak terduga.

Setelah ini, saya pikir ini bekerja dengan baik, setidaknya tidak terkecuali !!!
Saya menelepon dengan cara berikut:

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).
Venugopal M
sumber
5

Di bawah .net, waktu yang dibutuhkan untuk melakukan pengumpulan sampah jauh lebih terkait dengan jumlah barang yang bukan sampah, daripada jumlah barang yang ada. Memang, kecuali sebuah objek menimpa Finalize(baik secara eksplisit, atau melalui destruktor C #), adalah target dari aWeakReference , duduk di Tumpukan Objek Besar, atau khusus dalam beberapa cara terkait gc lainnya, satu-satunya hal yang mengidentifikasi memori di mana ia berada sebagai objek adalah adanya referensi yang mengakar padanya. Jika tidak, operasi GC dianalogikan dengan mengambil dari sebuah bangunan segala sesuatu yang bernilai, dan mendinamisasi bangunan tersebut, membangun yang baru di lokasi yang lama, dan meletakkan semua barang berharga di dalamnya. Upaya yang diperlukan untuk mendinam bangunan benar-benar tidak tergantung pada jumlah sampah di dalamnya.

Akibatnya, menelepon GC.Collectcenderung meningkatkan jumlah keseluruhan pekerjaan yang harus dilakukan sistem. Ini akan menunda terjadinya pengumpulan berikutnya, tetapi mungkin akan melakukan pekerjaan yang sama secepat yang diperlukan pengumpulan berikutnya ketika itu terjadi; pada titik ketika koleksi berikutnya akan terjadi, jumlah total waktu yang dihabiskan mengumpulkan akan telah hampir sama seperti yang GC.Collecttidak dipanggil, tetapi sistem akan telah mengumpulkan beberapa sampah, menyebabkan koleksi berhasil akan diperlukan lebih cepat dari punya GC.Collecttidak telah dipanggil.

Saat-saat yang saya lihat GC.Collectbenar-benar berguna adalah ketika seseorang perlu mengukur penggunaan memori dari beberapa kode (karena angka penggunaan memori hanya benar-benar berarti setelah koleksi), atau profil mana dari beberapa algoritme yang lebih baik (memanggil GC.Collect () sebelum menjalankan masing-masing dari beberapa bagian kode dapat membantu memastikan status dasar yang konsisten). Ada beberapa kasus lain di mana seseorang mungkin mengetahui hal-hal yang tidak diketahui GC, tetapi kecuali seseorang menulis program single-threaded, tidak mungkin orang mengetahui bahwa GC.Collectpanggilan yang akan membantu struktur data satu thread menghindari "krisis paruh baya. "tidak akan menyebabkan data thread lain mengalami" krisis paruh baya "yang seharusnya dapat dihindari.

supercat
sumber
5

Membuat gambar dalam satu lingkaran - bahkan jika Anda memanggil buang, memori tidak dipulihkan. Kumpulkan sampah setiap saat. Saya beralih dari memori 1,7GB pada aplikasi pemrosesan foto saya menjadi 24MB dan kinerjanya luar biasa.

Benar-benar ada waktu yang Anda perlukan untuk menghubungi GC.Collect.

lembah
sumber
2
Calling Disposeyang tidak seharusnya melepaskan memori dikelola. Anda sepertinya tidak tahu bagaimana model memori di .NET bekerja.
Andrew Barber
4

Kami memiliki masalah serupa dengan pengumpul sampah yang tidak mengumpulkan sampah dan mengosongkan memori.

Dalam program kami, kami memproses beberapa Excel Spreadsheets berukuran sedang dengan OpenXML. Spreadsheets berisi 5 sampai 10 "lembar" dengan sekitar 1000 baris 14 kolom.

Program dalam lingkungan 32 bit (x86) akan macet dengan kesalahan "kehabisan memori". Kami berhasil menjalankannya di lingkungan x64, tetapi kami menginginkan solusi yang lebih baik.

Kami menemukan satu.

Berikut adalah beberapa fragmen kode yang disederhanakan dari apa yang tidak berfungsi dan apa yang berhasil ketika harus secara eksplisit memanggil Pengumpul Sampah untuk membebaskan memori dari objek yang dibuang.

Memanggil GC dari dalam subrutin tidak berhasil. Memori tidak pernah diambil kembali ...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

Dengan Memindahkan panggilan GC ke luar lingkup subrutin, sampah dikumpulkan dan memori dibebaskan.

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

Saya harap ini membantu orang lain yang frustrasi dengan pengumpulan sampah .NET ketika tampaknya mengabaikan panggilan ke GC.Collect().

Paul Smith

Paul Smith
sumber
4

Tidak ada yang salah dengan meminta koleksi secara eksplisit. Beberapa orang hanya ingin percaya bahwa jika itu adalah layanan yang disediakan oleh vendor, jangan mempersoalkannya. Oh, dan semua itu membeku secara acak pada saat yang salah dalam aplikasi interaktif Anda? Versi selanjutnya akan membuatnya lebih baik!

Membiarkan proses latar belakang berurusan dengan manipulasi memori berarti tidak harus menghadapinya sendiri, benar. Tetapi secara logis ini tidak berarti bahwa yang terbaik bagi kita adalah tidak menanganinya sendiri dalam segala keadaan. GC dioptimalkan untuk banyak kasus. Tetapi ini tidak secara logis berarti bahwa ini dioptimalkan di semua kasus.

Pernahkah Anda menjawab pertanyaan terbuka seperti 'mana yang merupakan algoritma pengurutan terbaik' dengan jawaban yang pasti? Jika demikian, jangan sentuh GC. Bagi Anda yang menanyakan kondisi, atau memberikan jawaban tipe 'dalam kasus ini', Anda dapat melanjutkan untuk mempelajari tentang GC dan kapan harus mengaktifkannya.

Harus dikatakan, aplikasi saya macet di Chrome dan Firefox yang membuat saya frustasi, dan bahkan untuk beberapa kasus memori tumbuh tanpa hambatan - Seandainya saja mereka belajar memanggil pengumpul sampah - atau memberi saya sehingga saat saya mulai membaca teks halaman, saya dapat menekannya dan bebas dari macet selama 20 menit berikutnya.

Gerard ONeill
sumber
2

Saya pikir Anda benar tentang skenario, tetapi saya tidak yakin tentang API.

Microsoft mengatakan bahwa dalam kasus seperti itu Anda harus menambahkan tekanan memori sebagai petunjuk kepada GC bahwa GC harus segera melakukan pengumpulan.

Sergio Acosta
sumber
2
Menarik, tetapi dokumentasinya mengatakan bahwa AddMemoryPressure harus digunakan ketika 'objek yang dikelola kecil mengalokasikan sejumlah besar memori yang tidak dikelola'. (penekanan saya)
Robert Paulson
2

Apakah ada yang salah? Fakta bahwa Anda menebak-nebak pengumpul sampah dan pengalokasi memori, yang di antara keduanya memiliki gagasan yang jauh lebih besar tentang penggunaan memori aktual aplikasi Anda pada waktu proses daripada yang Anda lakukan.

rampok
sumber
1
Sifat heuristik dari pengumpul sampah dan fakta bahwa mereka mengekspos fungsi ini ke dunia luar membuat saya menganggapnya sebagai sesuatu yang berguna jika digunakan di tempat yang diperlukan. Masalahnya bukanlah menggunakannya tetapi mengetahui bagaimana, di mana dan kapan menggunakannya.
Perangkap
Belum lagi pengetahuan GC yang lebih baik tentang setiap aplikasi lain dan kebutuhan memori mereka. GC menegosiasikan memori dengan OS dan karena itu dipengaruhi oleh memori fisik yang tersedia dan semua proses lain di mesin baik yang dikelola maupun tidak. Meskipun saya ragu GC benar-benar tahu "kapan waktu yang tepat untuk mengumpulkan" berdasarkan "kasus per kasus", sangat mungkin memiliki strategi yang lebih baik secara keseluruhan daripada ... APAPUN aplikasi tunggal. ;)
Dag
2

Keinginan untuk memanggil GC.Collect () biasanya mencoba menutupi kesalahan yang Anda buat di tempat lain!

Akan lebih baik jika Anda menemukan di mana Anda lupa membuang barang yang tidak Anda butuhkan lagi.

Sam
sumber
5
itu mungkin generalisasi
MickyD
1

Intinya, Anda dapat membuat profil aplikasi dan melihat bagaimana koleksi tambahan ini memengaruhi banyak hal. Saya menyarankan untuk menjauh darinya kecuali jika Anda akan membuat profil. GC dirancang untuk menjaga dirinya sendiri dan seiring dengan perkembangan runtime, mereka dapat meningkatkan efisiensi. Anda tidak ingin banyak kode berkeliaran yang dapat mengacaukan pekerjaan dan tidak dapat memanfaatkan peningkatan ini. Ada argumen serupa untuk menggunakan foreach alih-alih for, yaitu, bahwa perbaikan masa depan di bawah sampul dapat ditambahkan ke foreach dan kode Anda tidak perlu diubah untuk memanfaatkannya.

Christopher Elliott
sumber
1

.NETFramework itu sendiri tidak pernah dirancang untuk berjalan dalam lingkungan waktu nyata. Jika Anda benar-benar membutuhkan pemrosesan waktu nyata, Anda akan menggunakan bahasa waktu nyata tertanam yang tidak didasarkan pada .NET atau menggunakan .NET Compact Framework yang dijalankan pada perangkat Windows CE.

Scott Dorman
sumber
Dia bisa menggunakan .Net Micro Framework, yang dirancang untuk lingkungan waktu nyata.
TraumaPony
@TraumaPony: Periksa bagan di bagian bawah halaman ini msdn.microsoft.com/en-us/embedded/bb278106.aspx : Jelas Micro Framework tidak dirancang untuk lingkungan waktu nyata. Itu, bagaimanapun, dirancang untuk lingkungan tertanam (seperti WinCE) tetapi dengan kebutuhan daya yang lebih rendah.
Scott Dorman
1

Hal terburuk yang akan dilakukannya adalah membuat program Anda berhenti sebentar. Jadi jika Anda setuju, lakukanlah. Biasanya tidak diperlukan untuk klien tebal atau aplikasi web dengan sebagian besar interaksi pengguna.

Saya telah menemukan bahwa terkadang program dengan utas yang berjalan lama, atau program batch, akan mendapatkan pengecualian OutOfMemory meskipun mereka membuang objek dengan benar. Satu yang saya ingat adalah pemrosesan transaksi database lini bisnis; yang lainnya adalah rutinitas pengindeksan pada thread latar belakang di aplikasi klien yang tebal.

Dalam kedua kasus tersebut, hasilnya sederhana: Tidak ada GC. Kumpulkan, kehabisan memori, secara konsisten; GC. Kumpulkan, kinerja tanpa cela.

Saya sudah mencobanya untuk memecahkan masalah memori beberapa kali, tetapi tidak berhasil. Saya mengeluarkannya.

Singkatnya, jangan memasukkannya kecuali Anda mendapatkan kesalahan. Jika Anda memasukkannya dan tidak memperbaiki masalah memori, keluarkan kembali. Ingatlah untuk menguji dalam mode Rilis dan bandingkan apel dengan apel.

Satu-satunya saat hal-hal bisa salah dengan ini adalah ketika Anda bersikap moralistik tentangnya. Ini bukan masalah nilai; banyak programmer telah meninggal dan langsung masuk surga dengan banyak GC.Collects yang tidak perlu dalam kode mereka, yang hidup lebih lama dari mereka.

FastAl
sumber