Kapan bisa menelepon GC.Collect?

166

Saran umum adalah Anda tidak boleh menelepon GC.Collectdari 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?

Brian Rasmussen
sumber
Kemungkinan rangkap dari Praktik Terbaik untuk Memaksa Pengumpulan Sampah di C #
Jimenemex

Jawaban:

153

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.LowLatencydan GCLatencyMode.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.TryStartNoGCRegionmetode (digunakan untuk mengatur nilai read-only GCLatencyMode.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:

Jon Skeet
sumber
8
Menurut kode sumber MS memanggil GC.Collect (2) setiap 850ms baik-baik saja. Tidak percaya Kemudian lihat PresentationCore.dll, MS.Internal.MemoryPressure.ProcessAdd (). Saat ini saya memiliki aplikasi pengolah gambar (gambar kecil, tidak ada dengan tekanan memori nyata) di mana memanggil GC.Collect (2) membutuhkan waktu lebih lama dari 850ms dan seluruh aplikasi jadi beku oleh ini (aplikasi menghabiskan 99,7% waktu dalam GC).
springy76
36
@ springy76: Dilakukan oleh Microsoft di satu tempat tidak berarti itu dianggap baik oleh mereka yang memberikan saran dari Microsoft ...
Jon Skeet
4
Saya tidak suka contoh itu. Apa gunanya melakukannya setelah formulir tutup? Satu contoh bagus yang saya lihat adalah setelah memuat level game di XBox atau WindowsPhone. Pada platform tersebut GC berjalan setelah mengalokasikan 1MB atau sth seperti itu. Jadi ada baiknya mengalokasikan sebanyak yang Anda bisa selama memuat level (sambil menunjukkan beberapa splash screen) dan kemudian lakukan GC.Collect untuk mencoba menghindari koleksi selama pertandingan.
Piotr Perak
8
@Peri: Tujuan melakukannya setelah menutup formulir adalah bahwa Anda baru saja membuat banyak objek (kontrol, data yang GC.CollectAnda 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?
Jon Skeet
6
@SHCJ: 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.
Jon Skeet
50

Saya GC.Collecthanya menggunakan saat menulis rig uji kinerja / profiler kasar; yaitu saya memiliki dua (atau lebih) blok kode untuk diuji - sesuatu seperti:

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestA(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestB(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
...

Jadi itu TestA()dan TestB()jalankan dengan kondisi yang sama mungkin - yaitu TestB()tidak mendapatkan palu hanya karenaTestA meninggalkannya sangat dekat dengan titik kritis.

Contoh klasik akan menjadi konsol exe sederhana ( Mainmetode 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

Marc Gravell
sumber
1
Dan saya mungkin menambahkan "WaitForPendingFinalizers" (atau apa pun itu) juga dalam kasus ini ;-p
Marc Gravell
29

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.

  • Diberikan daftar nama file pada baris perintah
  • Memproses satu file kemudian menulis hasilnya ke file hasil.
  • Saat memproses file, membuat banyak objek yang saling terkait yang tidak dapat dikumpulkan sampai pemrosesan file selesai (mis. Pohon parse)
  • Tidak mempertahankan status kecocokan antara file yang telah diproses .

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.

Satu-satunya waktu saya akan mempertimbangkan untuk memaksa koleksi adalah ketika saya tahu bahwa banyak objek telah dibuat baru-baru ini dan sangat sedikit objek yang saat ini direferensikan.

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 "

Ian Ringrose
sumber
19

Satu kasus adalah ketika Anda mencoba untuk menyatukan kode uji yang menggunakan WeakReference .

Brian
sumber
11

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:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

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.

Paul Ruane
sumber
Saya telah melihat koleksi dua-pass di beberapa tempat sekarang, tetapi setelah membaca bagian dalam dokumentasi MSDN untuk GC.WaitForPendingFinalizers yang mengatakan: "Tunggu semua finalis untuk menyelesaikan sebelum melanjutkan. Tanpa panggilan ini ke GC.WaitForPendingFinalizers, loop pekerja di bawah ini dapat dieksekusi pada saat yang sama dengan finalizer. Dengan panggilan ini, loop pekerja dieksekusi hanya setelah semua finalizer dipanggil. " Saya hanya paranoid sentuhan. Apakah Anda tahu sumber pasti untuk melakukan dua lintasan?
jerhewet
1
@jerhewet: Kunci untuk memahami mengapa dua koleksi diperlukan adalah dengan memahami apa yang terjadi pada objek dengan finalizer. Sayangnya saya tidak memiliki persis apa yang Anda minta, tetapi baca artikel ini dan pertanyaan ini pada SO .
Paul Ruane
10

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.

Joel Coehoorn
sumber
8

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.

Jiwa khas suatu bangsa
sumber
7

Lihat artikel ini oleh Rico Mariani. Dia memberikan dua aturan kapan harus menelepon GC.Collect (aturan 1 adalah: "Jangan"):

Kapan menelepon GC.Collect ()

M4N
sumber
3
Sudah ada di sana. Saya tidak mencoba mencari alasan untuk melakukan sesuatu yang seharusnya tidak Anda lakukan, tetapi saya ingin tahu apakah ada kasus tertentu di mana itu dapat diterima.
Brian Rasmussen
5

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:

GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()

Dalam pengalaman pribadi saya, menggunakan kombinasi ReleaseComObject dan pengumpulan sampah secara manual sangat mengurangi penggunaan memori produk Office, khususnya Excel.

Garthhh
sumber
ya aku berlari ke itu dengan. Net mengakses excel yang berfungsi melalui objek com juga. Penting untuk dicatat, bahwa ini tidak akan bekerja dengan baik dalam mode DEBUG karena operasi GC terbatas di sana. Ini akan berfungsi seperti yang dimaksudkan hanya dalam mode RELEASE. tautan yang relevan: stackoverflow.com/questions/17130382/…
Blechdose
5

Saya sedang melakukan beberapa pengujian kinerja pada array dan daftar:

private static int count = 100000000;
private static List<int> GetSomeNumbers_List_int()
{
    var lstNumbers = new List<int>();
    for(var i = 1; i <= count; i++)
    {
        lstNumbers.Add(i);
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Array()
{
    var lstNumbers = new int[count];
    for (var i = 1; i <= count; i++)
    {
        lstNumbers[i-1] = i + 1;
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Enumerable_Range()
{
    return  Enumerable.Range(1, count).ToArray();
}

static void performance_100_Million()
{
    var sw = new Stopwatch();

    sw.Start();
    var numbers1 = GetSomeNumbers_List_int();
    sw.Stop();
    //numbers1 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"List<int>\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
    var numbers2 = GetSomeNumbers_Array();
    sw.Stop();
    //numbers2 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"int[]\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
//getting System.OutOfMemoryException in GetSomeNumbers_Enumerable_Range method
    var numbers3 = GetSomeNumbers_Enumerable_Range();
    sw.Stop();
    //numbers3 = null;
    //GC.Collect();

    Console.WriteLine(String.Format("\"int[]\" Enumerable.Range took {0} milliseconds", sw.ElapsedMilliseconds));
}

dan saya OutOfMemoryExceptionmenggunakan metode GetSomeNumbers_Enumerable_Range satu-satunya solusi adalah dengan mendeallocate memori dengan:

numbers = null;
GC.Collect();
Daniel B
sumber
Mengapa harus memilih? jawaban saya adalah contoh yang menunjukkan kapan harus menelepon GC. Apakah Anda memiliki saran yang lebih baik? Anda dipersilakan hadir.
Daniel B
4

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

casperOne
sumber
3

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:

WeakReference w = CodeThatShouldNotMemoryLeak();
Assert.IsTrue(w.IsAlive);
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsFalse(w.IsAlive);

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.

ChaseMedallion
sumber
2

Jawaban singkatnya adalah: tidak pernah!

BankZ
sumber
9
Bahkan dalam situasi ini ?
Roman Starkov
2
using(var stream = new MemoryStream())
{
   bitmap.Save(stream, ImageFormat.Png);
   techObject.Last().Image = Image.FromStream(stream);
   bitmap.Dispose();

   // Without this code, I had an OutOfMemory exception.
   GC.Collect();
   GC.WaitForPendingFinalizers();
   //
}
Denis
sumber
2

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.

Carl Looper
sumber
2

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:

public static TResult ExecuteOOMAware<T1, T2, TResult>(Func<T1,T2 ,TResult> func, T1 a1, T2 a2)
{

    int oomCounter = 0;
    int maxOOMRetries = 10;
    do
    {
        try
        {
            return func(a1, a2);
        }
        catch (OutOfMemoryException)
        {
            oomCounter++;
            if (maxOOMRetries > 10)
            {
                throw;
            }
            else
            {
                Log.Info("OutOfMemory-Exception caught, Trying to fix. Counter: " + oomCounter.ToString());
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(oomCounter * 10));
                GC.Collect();
            }
        }
    } while (oomCounter < maxOOMRetries);

    // never gets hitted.
    return default(TResult);
}

(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.)

Thomas Haller
sumber
Komponen tidak seharusnya memanggil GC.Collect. Karena memiliki efek lebar aplikasi hanya aplikasi yang seharusnya melakukannya (jika ada).
CodesInChaos
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.
G. Stoynev
2

Anda harus mencoba untuk menghindari menggunakan GC.Collect () karena sangat mahal. Berikut ini sebuah contoh:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet.Remove(RecordSet[0]);

        }
        GC.Collect(); // AVOID
    }

HASIL UJI: PENGGUNAAN CPU 12%

Ketika Anda mengubah ini:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet[0].Dispose(); //  Bitmap destroyed!
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet[0].Dispose(); //  Bitmap destroyed!
            RecordSet.Remove(RecordSet[0]);

        }
        //GC.Collect();
    }

HASIL UJI: PENGGUNAAN CPU 2-3%

mtekeli
sumber
1

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 :

try
{
    if (port != null)
        port.Close(); //this will throw an exception if the port was unplugged
}
catch (Exception ex) //of type 'System.IO.IOException'
{
    System.GC.Collect();
    System.GC.WaitForPendingFinalizers();
}

port = null;
Jay Tennant
sumber
0

Ini tidak relevan dengan pertanyaan, tetapi untuk transformasi XSLT di .NET (XSLCompiledTranform) maka Anda mungkin tidak punya pilihan. Kandidat lain adalah kontrol MSHTML.

Chris S
sumber
0

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.

harry4516
sumber
0

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

Max CHien
sumber
0

Jika Anda membuat banyak System.Drawing.Bitmapobjek baru , Pengumpul Sampah tidak membersihkannya. Akhirnya GDI + akan berpikir Anda kehabisan memori dan akan mengeluarkan pengecualian "Parameter tidak valid". Menelepon GC.Collect()sesering mungkin (tidak terlalu sering!) Sepertinya bisa mengatasi masalah ini.

Nacht
sumber