Apakah Anda perlu membuang objek dan mengaturnya ke nol?

310

Apakah Anda perlu membuang objek dan mengaturnya ke nol, atau akankah pengumpul sampah membersihkannya ketika mereka keluar dari ruang lingkup?

CJ7
sumber
4
Tampaknya ada konsensus bahwa Anda tidak perlu mengatur objek ke nol, tetapi apakah Anda perlu melakukan Buang ()?
CJ7
3
seperti yang dikatakan Jeff: codinghorror.com/blog/2009/01/…
tanathos
9
Saran saya selalu buang jika suatu objek mengimplementasikan IDisposable. Gunakan blok penggunaan setiap kali. Jangan membuat asumsi, jangan serahkan pada kesempatan. Anda tidak perlu mengatur hal-hal menjadi nol. Suatu objek baru saja keluar dari ruang lingkup.
peter
11
@ Peter: Jangan gunakan "menggunakan" blok dengan proksi klien WCF: msdn.microsoft.com/en-us/library/aa355056.aspx
nlawalker
9
NAMUN, ANDA MUNGKIN ingin mengatur beberapa referensi menjadi nol di dalam Dispose()metode Anda ! Ini adalah variasi halus pada pertanyaan ini, tetapi penting karena objek yang dibuang tidak dapat mengetahui apakah itu "keluar dari ruang lingkup" (panggilan Dispose()bukan jaminan). Lebih lanjut di sini: stackoverflow.com/questions/6757048/…
Kevin P. Rice

Jawaban:

239

Objek akan dibersihkan ketika mereka tidak lagi digunakan dan ketika pengumpul sampah merasa cocok. Terkadang, Anda mungkin perlu mengatur objeknull membuatnya keluar dari ruang lingkup (seperti bidang statis yang nilainya tidak Anda butuhkan lagi), tetapi secara keseluruhan biasanya tidak perlu diatur ke null.

Mengenai membuang benda, saya setuju dengan @Andre. Jika objek IDisposableitu adalah ide yang baik untuk membuangnya ketika Anda tidak lagi membutuhkannya, terutama jika objek tersebut menggunakan sumber daya yang tidak dikelola. Tidak membuang sumber daya yang tidak dikelola akan menyebabkan kebocoran memori .

Anda dapat menggunakan usingpernyataan untuk secara otomatis membuang objek setelah program Anda meninggalkan ruang lingkup usingpernyataan.

using (MyIDisposableObject obj = new MyIDisposableObject())
{
    // use the object here
} // the object is disposed here

Yang secara fungsional setara dengan:

MyIDisposableObject obj;
try
{
    obj = new MyIDisposableObject();
}
finally
{
    if (obj != null)
    {
        ((IDisposable)obj).Dispose();
    }
}
Zach Johnson
sumber
4
Jika obj adalah tipe referensi maka blok akhirnya setara dengan:if (obj != null) ((IDisposable)obj).Dispose();
Randy mendukung Monica
1
@Tuzo: Terima kasih! Diedit untuk mencerminkan hal itu.
Zach Johnson
2
Satu komentar tentang IDisposable. Gagal membuang objek umumnya tidak akan menyebabkan kebocoran memori pada kelas yang dirancang dengan baik. Ketika bekerja dengan sumber daya yang tidak dikelola di C # Anda harus memiliki finalizer yang masih akan melepaskan sumber daya yang tidak dikelola. Ini berarti bahwa alih-alih mendelokasi sumber daya ketika harus dilakukan, itu akan ditunda ketika pengumpul sampah menyelesaikan objek yang dikelola. Ini masih dapat menyebabkan banyak masalah lain (seperti kunci yang belum dirilis). Anda harus Buang IDisposablemeskipun!
Aidiakapi
@RandyLevy Apakah Anda punya referensi untuk itu? Terima kasih
Dasar
Tapi pertanyaan saya adalah Buang () perlu menerapkan logika apa pun? Apakah harus melakukan sesuatu? Atau secara internal ketika Buang () disebut sinyal GC yang baik untuk pergi? Saya memeriksa kode sumber untuk TextWriter misalnya dan Buang tidak memiliki implementasi.
Mihail Georgescu
137

Objek tidak pernah keluar dari ruang lingkup di C # seperti yang mereka lakukan di C ++. Mereka ditangani oleh Pengumpul Sampah secara otomatis ketika mereka tidak digunakan lagi. Ini adalah pendekatan yang lebih rumit daripada C ++ di mana ruang lingkup variabel sepenuhnya deterministik. Pengumpul sampah CLR secara aktif menelusuri semua objek yang telah dibuat dan berfungsi jika sedang digunakan.

Objek bisa "keluar dari ruang lingkup" dalam satu fungsi tetapi jika nilainya dikembalikan, maka GC akan melihat apakah fungsi panggilan memegang nilai kembali.

Mengatur referensi objek nulltidak perlu karena pengumpulan sampah berfungsi dengan menentukan objek mana yang sedang direferensikan oleh objek lain.

Dalam praktiknya, Anda tidak perlu khawatir tentang kehancuran, itu hanya bekerja dan itu bagus :)

Disposeharus dipanggil pada semua objek yang mengimplementasikan IDisposableketika Anda selesai bekerja dengannya. Biasanya Anda akan menggunakan usingblok dengan objek-objek seperti:

using (var ms = new MemoryStream()) {
  //...
}

EDIT Pada lingkup variabel. Craig telah bertanya apakah ruang lingkup variabel memiliki efek pada masa hidup objek. Untuk menjelaskan dengan benar aspek CLR itu, saya perlu menjelaskan beberapa konsep dari C ++ dan C #.

Lingkup variabel aktual

Dalam kedua bahasa variabel hanya dapat digunakan dalam lingkup yang sama seperti yang didefinisikan - kelas, fungsi atau blok pernyataan terlampir oleh kurung kurawal. Perbedaan yang halus, bagaimanapun, adalah bahwa dalam C #, variabel tidak dapat didefinisikan ulang dalam blok bersarang.

Di C ++, ini sah menurut hukum:

int iVal = 8;
//iVal == 8
if (iVal == 8){
    int iVal = 5;
    //iVal == 5
}
//iVal == 8

Dalam C #, namun Anda mendapatkan kesalahan kompiler:

int iVal = 8;
if(iVal == 8) {
    int iVal = 5; //error CS0136: A local variable named 'iVal' cannot be declared in this scope because it would give a different meaning to 'iVal', which is already used in a 'parent or current' scope to denote something else
}

Ini masuk akal jika Anda melihat MSIL yang dihasilkan - semua variabel yang digunakan oleh fungsi didefinisikan pada awal fungsi. Lihatlah fungsi ini:

public static void Scope() {
    int iVal = 8;
    if(iVal == 8) {
        int iVal2 = 5;
    }
}

Di bawah ini adalah IL yang dihasilkan. Perhatikan bahwa iVal2, yang didefinisikan di dalam blok if sebenarnya didefinisikan pada level fungsi. Secara efektif ini berarti bahwa C # hanya memiliki ruang lingkup tingkat kelas dan fungsi sejauh variabel yang bersangkutan.

.method public hidebysig static void  Scope() cil managed
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init ([0] int32 iVal,
           [1] int32 iVal2,
           [2] bool CS$4$0000)

//Function IL - omitted
} // end of method Test2::Scope

C ++ lingkup dan objek seumur hidup

Setiap kali variabel C ++, dialokasikan pada stack, keluar dari ruang lingkup itu akan hancur. Ingatlah bahwa di C ++ Anda dapat membuat objek di stack atau di heap. Ketika Anda membuatnya di stack, setelah eksekusi meninggalkan ruang lingkup, mereka akan muncul dari stack dan dihancurkan.

if (true) {
  MyClass stackObj; //created on the stack
  MyClass heapObj = new MyClass(); //created on the heap
  obj.doSomething();
} //<-- stackObj is destroyed
//heapObj still lives

Ketika objek C ++ dibuat pada heap, mereka harus dihancurkan secara eksplisit, kalau tidak itu adalah kebocoran memori. Tidak ada masalah dengan variabel stack.

C # Obyek Seumur Hidup

Dalam CLR, objek (yaitu tipe referensi) selalu dibuat pada heap yang dikelola. Ini diperkuat oleh sintaks penciptaan objek. Pertimbangkan potongan kode ini.

MyClass stackObj;

Dalam C ++ ini akan membuat instance aktif MyClassdi stack dan memanggil konstruktor default-nya. Dalam C # itu akan membuat referensi ke kelas MyClassyang tidak menunjuk ke apa pun. Satu-satunya cara untuk membuat instance kelas adalah dengan menggunakan newoperator:

MyClass stackObj = new MyClass();

Di satu sisi, objek C # sangat mirip objek yang dibuat menggunakan newsintaks di C ++ - mereka dibuat di heap tetapi tidak seperti objek C ++, mereka dikelola oleh runtime, jadi Anda tidak perlu khawatir merusaknya.

Karena objek selalu di tumpukan fakta bahwa referensi objek (yaitu pointer) keluar dari ruang lingkup menjadi diperdebatkan. Ada lebih banyak faktor yang terlibat dalam menentukan apakah suatu objek harus dikumpulkan daripada sekadar kehadiran referensi ke objek.

C # Referensi objek

Jon Skeet membandingkan referensi objek di Jawa dengan potongan-potongan string yang melekat pada balon, yang merupakan objek. Analogi yang sama berlaku untuk referensi objek C #. Mereka hanya menunjuk ke lokasi tumpukan yang berisi objek. Dengan demikian, pengaturannya ke nol tidak memiliki efek langsung pada umur objek, balon terus ada, sampai GC "muncul" itu.

Melanjutkan analogi balon, akan tampak logis bahwa sekali balon tidak memiliki ikatan, balon itu dapat dihancurkan. Sebenarnya ini adalah persis bagaimana referensi menghitung objek bekerja dalam bahasa yang tidak dikelola Kecuali pendekatan ini tidak bekerja untuk referensi melingkar dengan sangat baik. Bayangkan dua balon yang disatukan oleh seutas tali tetapi tidak satu pun balon memiliki tali untuk yang lainnya. Di bawah aturan penghitungan ref sederhana, mereka berdua terus ada, meskipun seluruh kelompok balon "yatim piatu".

Objek NET sangat mirip balon helium di bawah atap. Ketika atap terbuka (GC run) - balon yang tidak digunakan melayang, meskipun mungkin ada kelompok balon yang ditambatkan bersama.

.NET GC menggunakan kombinasi GC generasi dan tanda serta sapuan. Pendekatan generasi melibatkan runtime yang mendukung untuk memeriksa objek yang telah dialokasikan terakhir, karena mereka lebih cenderung tidak digunakan dan menandai dan menyapu melibatkan runtime melalui seluruh grafik objek dan bekerja jika ada kelompok objek yang tidak digunakan. Ini cukup menangani masalah ketergantungan sirkuler.

Juga, .NET GC berjalan di utas lain (disebut utas finalizer) karena memiliki cukup banyak yang harus dilakukan dan melakukannya pada utas utama akan mengganggu program Anda.

Igor Zevaka
sumber
1
@ Igor: Dengan keluar 'lingkup' Maksud saya referensi objek di luar konteks dan tidak dapat disebut dalam lingkup saat ini. Tentunya ini masih terjadi di C #.
CJ7
@Craig Johnston, jangan bingung scoping variabel yang digunakan oleh kompiler dengan variabel seumur hidup yang ditentukan oleh runtime - mereka berbeda. Variabel lokal mungkin tidak "hidup" meskipun masih dalam cakupan.
Randy mendukung Monica
1
@Craig Johnston: Lihat blogs.msdn.com/b/ericgu/archive/2004/07/23/192842.aspx : "tidak ada jaminan bahwa variabel lokal akan tetap hidup sampai akhir ruang lingkup jika tidak runtime bebas untuk menganalisis kode yang dimilikinya dan menentukan apa yang tidak ada lagi penggunaan variabel di luar titik tertentu, dan oleh karena itu tidak menjaga variabel tersebut hidup di luar titik itu (yaitu tidak memperlakukannya sebagai root untuk tujuan tersebut) dari GC). "
Randy mendukung Monica
1
@Tuzo: Benar. Itulah gunanya GC. KeepAlive.
Steven Sudit
1
@Craig Johnston: Tidak dan Ya. Tidak karena .NET runtime mengelola untuk Anda dan melakukan pekerjaan dengan baik. Ya karena tugas programmer bukan untuk menulis kode yang (hanya) mengkompilasi tetapi untuk menulis kode yang berjalan . Terkadang membantu mengetahui apa yang dilakukan runtime di bawah selimut (mis. Pemecahan masalah). Orang bisa berpendapat bahwa itu adalah jenis pengetahuan yang membantu memisahkan programmer yang baik dari programmer yang hebat.
Randy mendukung Monica
18

Seperti yang orang lain katakan, Anda pasti ingin menelepon Disposejika kelas diimplementasikan IDisposable. Saya mengambil posisi yang cukup kaku dalam hal ini. Beberapa klaim kekuatan yang menyerukan Disposepada DataSet, misalnya, adalah sia-sia karena mereka dibongkar dan melihat bahwa itu tidak melakukan sesuatu yang berarti. Tapi, saya pikir ada banyak kesalahan dalam argumen itu.

Bacalah ini untuk debat yang menarik oleh orang-orang terhormat tentang masalah ini. Kemudian bacalah alasan saya di sini mengapa saya pikir Jeffery Richter ada di kubu yang salah.

Sekarang, apakah Anda harus menetapkan referensi atau tidak null. Jawabannya adalah tidak. Biarkan saya menggambarkan poin saya dengan kode berikut.

public static void Main()
{
  Object a = new Object();
  Console.WriteLine("object created");
  DoSomething(a);
  Console.WriteLine("object used");
  a = null;
  Console.WriteLine("reference set to null");
}

Jadi kapan menurut Anda objek yang dirujuk amemenuhi syarat untuk koleksi? Jika Anda mengatakan setelah panggilan ke a = nullmaka Anda salah. Jika Anda mengatakan setelah Mainmetode selesai maka Anda juga salah. Jawaban yang benar adalah bahwa itu memenuhi syarat untuk pengumpulan suatu saat selama panggilan ke DoSomething. Itu benar. Itu memenuhi syarat sebelum referensi diatur ke nulldan mungkin bahkan sebelum panggilan untuk DoSomethingselesai. Itu karena kompiler JIT dapat mengenali ketika referensi objek tidak lagi dereferensi bahkan jika mereka masih di-root.

Brian Gideon
sumber
3
Bagaimana jika abidang anggota pribadi dalam kelas? Jika atidak disetel ke nol, GC tidak memiliki cara untuk mengetahui apakah aakan digunakan lagi dalam beberapa metode, bukan? Dengan demikian atidak akan dikumpulkan sampai seluruh kelas yang mengandung dikumpulkan. Tidak?
Kevin P. Rice
4
@ Kevin: Benar. Jika aanggota kelas dan kelas yang berisi amasih di-root dan digunakan maka itu juga akan berkeliaran. Itu adalah salah satu skenario di mana pengaturannya nullbisa bermanfaat.
Brian Gideon
1
Poin Anda terkait dengan alasan mengapa hal Disposeini penting - tidak mungkin untuk memanggil Dispose(atau metode lain yang tidak dapat digariskan) pada suatu objek tanpa referensi yang di-rooting untuknya; memanggil Disposesetelah seseorang selesai menggunakan objek akan memastikan bahwa referensi yang di-rooting akan terus ada sepanjang durasi tindakan terakhir yang dilakukan padanya. Meninggalkan semua referensi ke suatu objek tanpa memanggil Disposemungkin ironisnya memiliki efek menyebabkan sumber daya objek kadang-kadang dirilis terlalu dini .
supercat
Contoh dan penjelasan ini tampaknya tidak definitif mengenai saran sulit untuk tidak pernah menetapkan referensi ke nol. Maksud saya, kecuali untuk komentar Kevin, referensi yang disetel ke nol setelah dibuang tampaknya cukup jinak , jadi apa salahnya? Apakah saya melewatkan sesuatu?
dathompson
13

Anda tidak perlu mengatur objek ke nol di C #. Compiler dan runtime akan membantu mencari tahu ketika mereka tidak lagi dalam ruang lingkup.

Ya, Anda harus membuang objek yang mengimplementasikan IDisposable.

EMP
sumber
2
Jika Anda memiliki referensi yang berumur panjang (atau bahkan statis) ke objek besar, Anda wantmembatalkannya segera setelah selesai sehingga bebas untuk direklamasi.
Steven Sudit
12
Jika Anda pernah "selesai dengan itu" seharusnya tidak statis. Jika tidak statis, tetapi "berumur panjang" maka itu harus tetap keluar dari ruang lingkup segera setelah Anda selesai dengan itu. Kebutuhan untuk menetapkan referensi ke nol menunjukkan masalah dengan struktur kode.
EMP
Anda dapat memiliki item statis yang selesai dengan Anda. Pertimbangkan: Sumber daya statis yang dibaca dari disk dalam format yang mudah digunakan dan kemudian diurai menjadi format yang sesuai untuk penggunaan program. Anda dapat berakhir dengan salinan pribadi dari data mentah yang tidak memiliki tujuan lebih lanjut. (Contoh dunia nyata: Parsing adalah rutinitas dua lintasan dan karenanya tidak bisa hanya memproses data saat dibaca.)
Loren Pechtel
1
Maka itu seharusnya tidak menyimpan data mentah dalam bidang statis jika hanya digunakan sementara. Tentu, Anda bisa melakukan itu, itu bukan praktik yang baik untuk alasan ini: Anda harus mengatur masa pakainya secara manual.
EMP
2
Anda menghindarinya dengan menyimpan data mentah dalam variabel lokal dalam metode yang memprosesnya. Metode mengembalikan data yang diproses, yang Anda simpan, tetapi lokal untuk data mentah keluar dari ruang lingkup ketika metode keluar dan secara otomatis GCed.
EMP
11

Saya setuju dengan jawaban umum di sini bahwa ya Anda harus membuang dan tidak, Anda biasanya tidak boleh mengatur variabel ke nol ... tapi saya ingin menunjukkan bahwa membuang BUKAN terutama tentang manajemen memori. Ya, ini dapat membantu (dan terkadang memang demikian) dengan manajemen memori, tetapi tujuan utamanya adalah untuk memberi Anda pelepasan sumber daya langka secara deterministik.

Misalnya, jika Anda membuka port perangkat keras (misalnya serial), soket TCP / IP, file (dalam mode akses eksklusif), atau bahkan koneksi basis data, kini Anda telah mencegah kode lain dari menggunakan item-item tersebut hingga item tersebut dirilis. Buang umumnya melepaskan barang-barang ini (bersama dengan GDI dan lainnya "os" menangani dll. Yang ada 1000-an tersedia, tetapi secara keseluruhan masih terbatas). Jika Anda tidak memanggil dipose pada objek pemilik dan secara eksplisit melepaskan sumber daya ini, maka cobalah untuk membuka sumber daya yang sama lagi di masa depan (atau program lain melakukannya) bahwa upaya terbuka akan gagal karena objek Anda yang tidak terlindungi, tidak terkumpul masih memiliki item terbuka . Tentu saja, ketika GC mengumpulkan item (jika pola Buang telah diterapkan dengan benar) sumber daya akan dilepaskan ... tetapi Anda tidak tahu kapan itu akan terjadi, jadi Anda tidak perlu t tahu kapan aman untuk membuka kembali sumber daya itu. Ini adalah masalah utama. Tentu saja, melepaskan pegangan ini sering juga melepaskan memori, dan tidak pernah melepaskannya mungkin tidak pernah melepaskan memori itu ... karena itu semua pembicaraan tentang kebocoran memori, atau keterlambatan pembersihan memori.

Saya telah melihat contoh dunia nyata dari masalah yang menyebabkan ini. Sebagai contoh, saya telah melihat aplikasi web ASP.Net yang akhirnya gagal terhubung ke database (walaupun untuk waktu yang singkat, atau sampai proses server web dimulai ulang) karena 'koneksi pool sql server penuh' ... yaitu , begitu banyak koneksi telah dibuat dan tidak secara eksplisit dirilis dalam periode waktu yang singkat sehingga tidak ada koneksi baru yang dapat dibuat dan banyak koneksi di pool, meskipun tidak aktif, masih dirujuk oleh objek yang tidak tertutup dan tidak terkumpul sehingga bisa ' t digunakan kembali. Membuang koneksi database dengan benar jika perlu memastikan masalah ini tidak terjadi (setidaknya tidak kecuali Anda memiliki akses bersamaan yang sangat tinggi).

Yort
sumber
11

Jika objek diimplementasikan IDisposable , maka ya, Anda harus membuangnya. Objek bisa bergantung pada sumber daya asli (file menangani, objek OS) yang mungkin tidak segera dibebaskan sebaliknya. Hal ini dapat menyebabkan kelaparan sumber daya, masalah penguncian file, dan bug halus lainnya yang dapat dihindari.

Lihat juga Menerapkan Metode Buang di MSDN.

Chris Schmich
sumber
Tetapi bukankah kolektor garabage akan memanggil Buang ()? Jika demikian, mengapa Anda perlu menyebutnya?
CJ7
Kecuali Anda menyebutnya secara eksplisit, tidak ada jaminan yang Disposeakan dipanggil. Juga, jika objek Anda berpegang pada sumber daya yang langka atau mengunci beberapa sumber daya (misalnya file), maka Anda ingin membebaskannya sesegera mungkin. Menunggu GC melakukan itu adalah suboptimal.
Chris Schmich
12
GC tidak akan pernah memanggil Buang (). GC dapat memanggil finalizer yang menurut konvensi harus membersihkan sumber daya.
adrianm
@adrianm: Bukan mightpanggilan, tapi willpanggilan.
leppie
2
@ leppie: finalizers tidak deterministik dan mungkin tidak dipanggil (mis. ketika appdomain diturunkan). Jika Anda memerlukan finalisasi deterministik, Anda harus menerapkan apa yang saya pikir disebut penangan kritis. CLR memiliki penanganan khusus terhadap objek-objek ini untuk menjamin bahwa objek-objek tersebut telah selesai (misalnya, melakukan pre-jits pada kode finalisasi untuk menangani memori rendah)
adrianm
9

Jika mereka mengimplementasikan antarmuka IDisposable maka Anda harus membuangnya. Pengumpul sampah akan mengurus sisanya.

EDIT: terbaik adalah menggunakan usingperintah saat bekerja dengan barang sekali pakai:

using(var con = new SqlConnection("..")){ ...
Andre
sumber
5

Ketika suatu objek mengimplementasikan IDisposableAnda harus memanggil Dispose(atauClose , dalam beberapa kasus, itu akan memanggil Buang untuk Anda).

Anda biasanya tidak harus mengatur objek null , karena GC akan tahu bahwa objek tidak akan digunakan lagi.

Ada satu pengecualian ketika saya mengatur objek null. Ketika saya mengambil banyak objek (dari database) yang perlu saya kerjakan, dan menyimpannya dalam koleksi (atau array). Ketika "pekerjaan" selesai, saya mengatur objek kenull , karena GC tidak tahu saya selesai bekerja dengannya.

Contoh:

using (var db = GetDatabase()) {
    // Retrieves array of keys
    var keys = db.GetRecords(mySelection); 

    for(int i = 0; i < keys.Length; i++) {
       var record = db.GetRecord(keys[i]);
       record.DoWork();
       keys[i] = null; // GC can dispose of key now
       // The record had gone out of scope automatically, 
       // and does not need any special treatment
    }
} // end using => db.Dispose is called
GvS
sumber
4

Biasanya, tidak perlu mengatur bidang ke nol. Saya selalu merekomendasikan membuang sumber daya yang tidak dikelola.

Dari pengalaman saya juga menyarankan Anda untuk melakukan hal berikut:

  • Berhenti berlangganan dari acara jika Anda tidak lagi membutuhkannya.
  • Setel bidang apa pun yang menahan delegasi atau ekspresi menjadi nol jika tidak lagi diperlukan.

Saya telah menemukan beberapa hal yang sangat sulit untuk menemukan masalah yang merupakan akibat langsung dari tidak mengikuti saran di atas.

Tempat yang baik untuk melakukan ini adalah di Buang (), tetapi lebih cepat biasanya lebih baik.

Secara umum, jika ada referensi ke suatu objek pengumpul sampah (GC) dapat mengambil beberapa generasi lebih lama untuk mengetahui bahwa suatu objek tidak lagi digunakan. Sementara objek tetap dalam memori.

Itu mungkin tidak menjadi masalah sampai Anda menemukan bahwa aplikasi Anda menggunakan lebih banyak memori daripada yang Anda harapkan. Ketika itu terjadi, sambungkan profiler memori untuk melihat benda apa yang tidak dibersihkan. Menyetel bidang yang merujuk objek lain ke null dan menghapus koleksi yang ada dapat benar-benar membantu GC mengetahui objek apa yang dapat dihapus dari memori. GC akan mendapatkan kembali memori yang digunakan lebih cepat membuat aplikasi Anda jauh lebih sedikit memori yang lapar dan lebih cepat.

Marnix van Valen
sumber
1
Apa yang Anda maksud tentang 'acara dan delegasi' - apa yang harus 'dibersihkan' dengan ini?
CJ7
@Craig - Saya mengedit jawaban saya. Semoga ini sedikit memperjelasnya.
Marnix van Valen
3

Selalu panggil buang. Itu tidak sebanding dengan risikonya. Aplikasi perusahaan yang dikelola besar harus diperlakukan dengan hormat. Tidak ada asumsi yang dapat dibuat atau hal itu akan kembali menggigit Anda.

Jangan dengarkan leppie.

Banyak objek tidak benar-benar menerapkan IDisposable, jadi Anda tidak perlu khawatir tentang mereka. Jika mereka benar-benar keluar dari ruang lingkup mereka akan dibebaskan secara otomatis. Juga saya tidak pernah menemukan situasi di mana saya harus menetapkan sesuatu ke nol.

Satu hal yang bisa terjadi adalah banyak benda bisa dipegang terbuka. Ini dapat sangat meningkatkan penggunaan memori aplikasi Anda. Terkadang sulit untuk mengetahui apakah ini sebenarnya kebocoran memori, atau apakah aplikasi Anda hanya melakukan banyak hal.

Alat profil memori dapat membantu dengan hal-hal seperti itu, tetapi itu bisa rumit.

Selain itu selalu berhenti berlangganan dari acara yang tidak diperlukan. Berhati-hatilah dengan pengikatan dan kontrol WPF. Bukan situasi yang biasa, tapi saya menemukan situasi di mana saya memiliki kontrol WPF yang terikat pada objek yang mendasarinya. Objek yang mendasarinya besar dan memakan banyak memori. Kontrol WPF sedang diganti dengan contoh baru, dan yang lama masih berkeliaran untuk beberapa alasan. Ini menyebabkan kebocoran memori yang besar.

Di situs belakang kode ditulis dengan buruk, tetapi intinya adalah Anda ingin memastikan bahwa hal-hal yang tidak digunakan keluar dari ruang lingkup. Yang satu membutuhkan waktu lama untuk menemukan dengan profiler memori karena sulit untuk mengetahui hal-hal apa dalam memori yang valid, dan apa yang seharusnya tidak ada.

Peter
sumber
2

Saya harus menjawab juga. JIT menghasilkan tabel bersama dengan kode dari analisis statis penggunaan variabel. Entri tabel tersebut adalah "GC-Roots" dalam bingkai tumpukan saat ini. Saat penunjuk instruksi maju, entri tabel tersebut menjadi tidak valid dan siap untuk pengumpulan sampah. Oleh karena itu: Jika itu adalah variabel scoped, Anda tidak perlu mengaturnya ke nol - GC akan mengumpulkan objek. Jika itu anggota atau variabel statis, Anda harus mengaturnya ke nol

Hui
sumber