Nesneleri atmanız ve null değerine ayarlamanız gerekiyor mu?


310

Nesneleri atmanız ve null değerine ayarlamanız mı gerekiyor, yoksa çöp toplayıcı kapsam dışı kaldığında onları temizleyecek mi?


4
Nesneyi null olarak ayarlamanız gerekmediğine dair bir fikir birliği var gibi görünüyor, ancak Dispose () yöntemini yapmanız gerekiyor mu?
CJ7

3
Jeff'in dediği gibi: codinghorror.com/blog/2009/01/…
tanathos

9
Bir nesne IDisposable uygularsa tavsiyem her zaman elden çıkar. Her seferinde bir kullanma bloğu kullanın. Varsayımlarda bulunmayın, şansa bırakmayın. Yine de bir şeyleri null değerine ayarlamanız gerekmez. Bir nesne kapsam dışına çıktı.
peter

11
@peter: WCF istemci proxy'leriyle "kullanma" bloklarını kullanmayın: msdn.microsoft.com/en-us/library/aa355056.aspx
nlawalker

9
ANCAK,Dispose() yöntem içinde null için bazı başvurular ayarlamak isteyebilirsiniz ! Bu, bu soruda ince bir varyasyon olmakla birlikte önemlidir, çünkü atılan nesne "kapsam dışına çıkıp çıkmadığını" bilemez (çağrı Dispose()garanti değildir). Daha fazla burada: stackoverflow.com/questions/6757048/…
Kevin P. Rice

Yanıtlar:


239

Nesneler artık kullanılmadıklarında ve çöp toplayıcı uygun görüldüğünde temizlenecektir. Bazen, bir nesneyi nullkapsam dışına çıkarmak için (değerini artık ihtiyacınız olmayan statik bir alan gibi) yapmak için ayarlamanız gerekebilir, ancak genel olarak genellikle ayarlanmaya gerek yoktur null.

Nesneleri elden çıkarma konusunda, @Andre ile hemfikirim. Nesne ise IDisposable, artık ihtiyacınız olmadığında, özellikle de nesne yönetilmeyen kaynaklar kullanıyorsa, imha etmek iyi bir fikirdir . Yönetilmeyen kaynakların atılmaması bellek sızıntılarına neden olur .

Sen kullanabilirsiniz usingotomatik programı yaprakları kez kapsamını bir nesneyi elden çıkarma deyimi usingaçıklamada.

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

Hangi fonksiyonel olarak eşdeğerdir:

MyIDisposableObject obj;
try
{
    obj = new MyIDisposableObject();
}
finally
{
    if (obj != null)
    {
        ((IDisposable)obj).Dispose();
    }
}

4
Obj bir referans türü ise, nihayet blok şuna eşittir:if (obj != null) ((IDisposable)obj).Dispose();
Randy, Monica

1
@Tuzo: Teşekkürler! Bunu yansıtacak şekilde düzenlendi.
Zach Johnson

2
İle ilgili bir açıklama IDisposable. Bir nesneyi atmamak genellikle iyi tasarlanmış bir sınıfta bellek sızıntısına neden olmaz . C # 'da yönetilmeyen kaynaklarla çalışırken, yönetilmeyen kaynakları serbest bırakacak bir sonlandırıcıya sahip olmalısınız. Bu, kaynakların yapılması gerektiğinde yeniden konumlandırılması yerine, çöp toplayıcının yönetilen nesneyi sonlandırdığı zaman erteleneceği anlamına gelir. Yine de başka birçok soruna neden olabilir (yayınlanmamış kilitler gibi). Bir şey atmalısın IDisposable!
Aidiakapi

@RandyLevy Bunun için bir referansınız var mı? Teşekkürler
Temel

Ama benim sorum Dispose () herhangi bir mantık uygulamak gerekir? Bir şey yapmak zorunda mı? Veya Dispose () yöntemi GC olarak adlandırıldığında, gitmek iyi olan sinyaller? Örneğin TextWriter için kaynak kodunu kontrol ettim ve Dispose'in uygulaması yok.
Mihail Georgescu

137

Nesneler asla C ++ 'da olduğu gibi C # kapsam dışına çıkmaz. Artık kullanılmadıklarında Çöp Toplayıcı tarafından otomatik olarak ele alınırlar. Bu, bir değişkenin kapsamının tamamen deterministik olduğu C ++ 'dan daha karmaşık bir yaklaşımdır. CLR çöp toplayıcı, oluşturulan tüm nesnelerden aktif olarak geçer ve kullanılıyorsa çalışır.

Bir nesne bir işlevde "kapsam dışına çıkabilir" ancak değeri döndürülürse, GC çağrı işlevinin dönüş değeri üzerinde tutup tutmadığına bakar.

nullÇöp toplama, diğer nesneler tarafından hangi nesnelere başvurulduğunu çalışarak çalıştığından nesne başvurularını ayarlamak gereksizdir.

Uygulamada, yıkım konusunda endişelenmenize gerek yok, sadece çalışıyor ve harika :)

DisposeIDisposableonlarla çalışmayı bitirdiğinizde uygulanan tüm nesnelerde çağrılmalıdır . Normalde usingşu nesnelerle bir blok kullanırsınız :

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

EDIT Değişken kapsamda. Craig, değişken kapsamın nesne ömrü üzerinde herhangi bir etkisi olup olmadığını sordu. CLR'nin bu yönünü doğru bir şekilde açıklamak için, C ++ ve C # 'dan birkaç kavramı açıklamam gerekecek.

Gerçek değişken kapsamı

Her iki dilde de değişken yalnızca tanımlandığı şekilde kullanılabilir - sınıf, işlev veya parantez içine alınmış bir ifade bloğu. Ancak küçük fark, C # 'da değişkenlerin iç içe bir blokta yeniden tanımlanamamasıdır.

C ++ 'da, bu tamamen yasaldır:

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

Ancak C # 'da bir derleyici hatası alırsınız:

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
}

Oluşturulan MSIL'a bakarsanız bu mantıklıdır - işlev tarafından kullanılan tüm değişkenler işlevin başlangıcında tanımlanır. Bu işleve bir göz atın:

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

Aşağıda üretilen IL gösterilmektedir. İf bloğunun içinde tanımlanan iVal2'nin aslında işlev düzeyinde tanımlandığını unutmayın. Etkili bir şekilde bu, C # 'ın değişken ömür açısından sadece sınıf ve fonksiyon seviyesi kapsamına sahip olduğu anlamına gelir.

.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 ++ kapsamı ve nesne ömrü

Yığına ayrılan bir C ++ değişkeni, kapsam dışına çıkarsa tahrip olur. C ++ 'da yığın veya yığın üzerinde nesneler oluşturabileceğinizi unutmayın. Bunları yığın üzerinde oluşturduğunuzda, yürütme kapsamdan ayrıldığında, yığıntan atlar ve yok edilirler.

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

C ++ nesneleri yığın üzerinde oluşturulduğunda, açıkça yok edilmelidir, aksi takdirde bir bellek sızıntısıdır. Ancak yığın değişkenleri ile böyle bir sorun yok.

C # Nesne Ömrü

CLR'de, nesneler (yani referans türleri) her zaman yönetilen yığın üzerinde oluşturulur. Bu, nesne oluşturma sözdizimi ile daha da güçlendirilir. Bu kod snippet'ini düşünün.

MyClass stackObj;

C ++ 'da bu MyClass, yığın üzerinde bir örnek oluşturur ve varsayılan kurucusunu çağırır. C # 'da MyClasshiçbir şeye işaret etmeyen sınıfa bir referans oluşturur . Sınıf örneği oluşturmanın tek yolu newoperatör kullanmaktır :

MyClass stackObj = new MyClass();

Bir şekilde, C # nesneleri, newC ++ 'da sözdizimi kullanılarak oluşturulan nesnelere çok benzer - yığın üzerinde oluşturulurlar, ancak C ++ nesnelerinin aksine, çalışma zamanı tarafından yönetilirler, bu yüzden onları yok etme konusunda endişelenmenize gerek yoktur.

Nesneler her zaman öbek üzerinde olduğundan, nesne referanslarının (yani işaretçiler) kapsam dışına çıkması tartışmaya dönüşür. Bir nesnenin toplanıp toplanmayacağını belirlemede, nesneye yapılan referansların varlığından daha fazla faktör vardır.

C # Nesne başvuruları

Jon Skeet , Java'daki nesne referanslarını, nesne olan balona bağlı dize parçalarıyla karşılaştırdı . Aynı benzetme C # nesne başvuruları için de geçerlidir. Basitçe nesnenin bulunduğu yığının bir konumuna işaret ederler. Bu nedenle, null değerine ayarlamanın nesne ömrü üzerinde hemen bir etkisi yoktur, GC "patlayana" kadar balon var olmaya devam eder.

Balon benzetmesine devam edilirken, balonun kendisine bir dizi bağlı olmadığında yok edilebileceği mantıklı görünmektedir. Aslında, bu, sayılan nesnelerin tam olarak yönetilmeyen dillerde nasıl çalıştığıdır. Ancak bu yaklaşım dairesel referanslar için pek işe yaramaz. Bir dize ile birbirine bağlanmış ancak hiçbir balonun başka bir şeye sahip olmadığı iki balon düşünün. Basit ref sayma kurallarına göre, balon grubunun tamamı "yetim" olmasına rağmen her ikisi de var olmaya devam eder.

.NET nesneleri bir çatı altında helyum balonları gibidir. Çatı açıldığında (GC çalışır) - birlikte bağlı balon grupları olsa da, kullanılmayan balonlar uçup gider.

.NET GC, nesil GC ile markalama ve süpürme kombinasyonunu kullanır. Nesil yaklaşım, çalışma zamanının en son tahsis edilen nesneleri incelemek için tercih edilmesini içerir, çünkü kullanılma olasılıkları daha yüksektir ve işaretleme ve süpürme, çalışma zamanının tüm nesne grafiğinden geçmesini ve kullanılmayan nesne grupları varsa çalışmasını içerir. Bu, dairesel bağımlılık sorununu yeterince ele almaktadır.

Ayrıca, .NET GC başka bir iş parçacığında (sonlandırıcı iş parçacığı olarak da adlandırılır) çalışacak ve ana iş parçacığında bunu yapmak programınızı kesintiye uğratacaktır.


1
@Igor: 'Kapsam dışı' ifadesiyle, nesne başvurusunun bağlam dışı olduğunu ve geçerli kapsamda atıfta bulunamayacağını kastediyorum. Şüphesiz bu hala C # 'da olur.
CJ7

@Craig Johnston, derleyici tarafından kullanılan değişken kapsamayı çalışma zamanı tarafından belirlenen değişken ömürle karıştırmayın - bunlar farklıdır. Yerel bir değişken, hala kapsamda olmasına rağmen "canlı" olmayabilir.
Randy, Monica'yı

1
@Craig Johnston: Bkz. Blogs.msdn.com/b/ericgu/archive/2004/07/23/192842.aspx : "Yerel bir değişkenin kapsamın sonuna kadar canlı kalacağının garantisi yoktur Çalışma zamanı, sahip olduğu kodu analiz etmekte ve belirli bir noktanın ötesinde bir değişkenin başka kullanımlarının ne olmadığını belirlemekte serbesttir ve bu nedenle bu değişkeni bu noktanın ötesinde canlı tutmaz (yani, amaçlar için bir kök olarak ele almaz) GC). "
Randy, Monica

1
@Tuzo: Doğru. GC.KeepAlive bunun için.
Steven Sudit

1
@Craig Johnston: Hayır ve Evet. Hayır çünkü .NET çalışma zamanı bunu sizin için yönetir ve iyi bir iş çıkarır. Evet, çünkü programlayıcının işi (sadece) derleyen kod yazmak değil, çalışan kod yazmaktır . Bazen kapakların altında çalışma zamanının ne yaptığını bilmenize yardımcı olur (örneğin sorun giderme). İyi programcıları büyük programcılardan ayırmaya yardımcı olan bilgi türü olduğu söylenebilir.
Randy, Monica

18

Diğerlerinin söylediği gibi Dispose, sınıf uygularsa kesinlikle aramak istersiniz IDisposable. Bu konuda oldukça katı bir pozisyon alıyorum. Bazı kudreti iddia sesleniyor Disposeüzerinde DataSetonlar bunu sökülüp anlamlı bir şey yapmadım o testere çünkü örneğin, anlamsızdır. Ama bence bu iddiada bolca yanlış var.

Konuyla ilgili saygın bireylerin ilginç bir tartışması için bunu okuyun . Sonra benim akıl okumak burada ben Jeffery Richter yanlış kampında olduğunu düşünüyorum neden.

Şimdi, bir referans ayarlamanız gerekip gerekmediği konusunda null. Cevap hayır. Demek istediğim şu kodla açıklayayım.

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");
}

Peki başvuruda bulunulan nesnenin ne zaman akoleksiyona uygun olduğunu düşünüyorsunuz ? Çağrıdan sonra a = nullsöylediyseniz yanılıyorsunuz. Eğer sonra yaptığı açıklamada ise Maino zaman yöntem tamamlanıncaya da yanlış. Doğru cevap, çağrı sırasında bir süre için toplanmaya uygun olmasıdır DoSomething. Bu doğru. Bu uygun olup önce referans olarak ayarlanır nullbile çağrısı önce belki ve DoSomethingtamamlar. Bunun nedeni, JIT derleyicisinin, hala köklü olsalar bile, nesne başvurularının artık kaydı kaldırılmadığını algılayabilmesidir.


3
Ya abir sınıfta özel üye alandır? Eğer anull olarak ayarlı değil GC eğer bilmenin bir yolu vardır a, doğru bazı yöntemde tekrar kullanılacak? Böylece a, içeren sınıfın tamamı toplanana kadar toplanmayacaktır. Hayır?
Kevin P. Rice

4
@Kevin: Doğru. aBir sınıf üyesi olsaydı ve içeren sınıf ahala köklü ve kullanımdaysa, o da takılmak olurdu. Bu, onu nullkurmanın faydalı olabileceği bir senaryodur .
Brian Gideon

1
Amacınız Disposeönemli bir nedenden Disposekaynaklanıyor - köklü bir referansı olmayan bir nesne üzerinde (ya da diğer inline edilemez yöntemlerden) çağrılması mümkün değil; Disposebiri nesne kullanılarak yapıldıktan sonra çağrıldığında , köklü bir başvurunun, üzerinde gerçekleştirilen son eylemin süresi boyunca var olmaya devam etmesi sağlanır. Bir nesneye çağrı yapılmadan yapılan tüm referansların terk edilmesi Disposeironik bir şekilde, nesnenin kaynaklarının zaman zaman çok erken salınmasına neden olabilir .
Supercat

Bu örnek ve açıklama hiçbir zaman null değerine göndermeler yapmamanın zor önerisinde kesin görünmemektedir. Yani, Kevin'in yorumu hariç, atıldıktan sonra null olarak ayarlanmış bir başvuru oldukça iyi görünüyor , bu yüzden zarar nedir? Bir şey mi kaçırıyorum?
dathompson

13

Nesneleri asla C # ile null değerine ayarlamanız gerekmez. Derleyici ve çalışma zamanı, artık kapsamda olmadıklarında, bu sorunu çözer.

Evet, IDisposable uygulayan nesneleri atmalısınız.


2
Büyük bir nesneye uzun ömürlü (hatta statik) bir referansınız wantvarsa, işiniz biter bitmez onu geri almanız serbest bırakılır.
Steven Sudit

12
Hiç "işiniz bittiğinde" durağan olmamalıdır. Statik değil, ama "uzun ömürlü" ise, işiniz bittikten hemen sonra kapsam dışı kalmalıdır. Null değerine başvuruyu ayarlama ihtiyacı, kodun yapısında bir sorun olduğunu gösterir.
EMP

İşiniz bittiğinde statik bir öğeniz olabilir. Şunu düşünün: Diskten kullanıcı dostu bir biçimde okunan ve daha sonra program kullanımına uygun bir biçime ayrıştırılan statik bir kaynak. Başka hiçbir amaca hizmet etmeyen ham verilerin özel bir kopyasını elde edebilirsiniz. (Gerçek dünya örneği: Ayrıştırma iki geçişli bir rutindir ve bu nedenle verileri okunduğu gibi işleyemez.)
Loren Pechtel

1
O zaman sadece geçici olarak kullanılıyorsa, ham verileri statik bir alanda depolamamalıdır. Tabii, bunu yapabilirsiniz , tam olarak bu nedenle iyi bir uygulama değildir: daha sonra ömrünü manuel olarak yönetmeniz gerekir.
EMP

2
İşlenmeyen yöntemde ham verileri yerel bir değişkende depolayarak bundan kaçınırsınız. Yöntem, sakladığınız işlenen verileri döndürür, ancak yöntemden çıkıldığında ve otomatik olarak GCed edildiğinde ham veriler için yerel kapsam dışına çıkar.
EMP

11

Buradaki ortak cevaba katılıyorum, evet bertaraf etmelisiniz ve hayır genellikle değişkeni null değerine ayarlamamalısınız ... ama bertarafın öncelikle bellek yönetimi ile ilgili OLMADIĞINI belirtmek istedim. Evet, bellek yönetimine yardımcı olabilir (ve bazen de yardımcı olabilir), ancak asıl amacı az bulunan kaynakların deterministik olarak serbest bırakılmasını sağlamaktır.

Örneğin, bir donanım bağlantı noktasını (örneğin seri), bir TCP / IP soketini, bir dosyayı (özel erişim modunda) veya hatta bir veritabanı bağlantısını açarsanız, artık serbest bırakılıncaya kadar başka bir kodun bu öğeleri kullanmasını engellediniz. Atma genellikle bu kalemleri serbest bırakır (GDI ve diğer "işletim sistemi" tutamaçları vb. İle birlikte 1000'lerin mevcut olduğu, ancak yine de genel olarak sınırlı olduğu). Owner nesnesinde dipose öğesini çağırmazsanız ve bu kaynakları açıkça serbest bırakırsanız, aynı kaynağı gelecekte tekrar açmayı deneyin (veya başka bir program yapar), denenmemiş, toplanmayan nesneniz hala öğeyi açık olduğu için açık deneme başarısız olur . Elbette, GC öğeyi topladığında (Atma düzeni doğru bir şekilde uygulandıysa) kaynak serbest bırakılacaktır ... ancak bunun ne zaman olacağını bilmiyorsunuz, bu yüzden o kaynağı yeniden açmanın ne zaman güvenli olduğunu bilmiyorum. Bu birincil sorun Dispose etrafında çalışır. Tabii ki, bu tutamaçları serbest bırakmak genellikle belleği serbest bırakır ve asla serbest bırakmamak o belleği asla serbest bırakamaz ... dolayısıyla bellek sızıntıları veya bellek temizliğindeki gecikmeler hakkında tüm konuşmalar.

Bu sorunlara neden olan gerçek dünya örnekleri gördüm. Örneğin, sql sunucusunun 'bağlantı havuzu dolu' olduğu için (kısa süre de olsa veya web sunucusu işlemi yeniden başlatılıncaya kadar) veritabanına bağlanamayan ASP.Net web uygulamalarını gördüm. , yeni bağlantılar oluşturulamayacak ve havuzdaki bağlantıların çoğuna, etkin olmasa da, hala kullanılmayan ve toplanmayan nesneler tarafından referans verilebileceği ve bu nedenle ' t tekrar kullanılmamalıdır. Gerektiğinde veritabanı bağlantılarını doğru bir şekilde atmak bu sorunun oluşmamasını sağlar (en azından çok yüksek eşzamanlı erişiminiz yoksa ).


11

Nesne uygulanırsa IDisposable, evet, atmalısınız. Nesne, hemen serbest bırakılmayabilecek yerel kaynaklara (dosya tanıtıcıları, işletim sistemi nesneleri) asılı olabilir. Bu, kaynak açlığına, dosya kilitleme sorunlarına ve aksi takdirde önlenebilecek diğer küçük hatalara yol açabilir.

Ayrıca bkz . MSDN'de Bir İmha Yöntemi Uygulama .


Ancak, çöp toplayıcı Dispose () öğesini çağırmaz mı? Öyleyse, neden araman gerekiyor?
CJ7

Açıkça çağırmazsanız, aranacak hiçbir garanti yoktur Dispose. Ayrıca, nesneniz kıt bir kaynağa tutunuyorsa veya bazı kaynakları (örneğin bir dosya) kilitliyorsa, mümkün olan en kısa sürede serbest bırakmak istersiniz. GC'nin bunu yapmasını beklemek yetersizdir.
Chris Schmich

12
GC asla Dispose () öğesini çağırmaz. GC, sözleşmeyle kaynakları temizlemesi gereken bir sonlandırıcı olarak adlandırılabilir.
adrianm

@adrianm: Aramayın might, willarayın.
leppie

2
@ leppie: finalizörler deterministik değildir ve çağrılmayabilir (örneğin, uygulama alanı kaldırıldığında). Eğer deterministik sonlandırmaya ihtiyacınız varsa, kritik işleyici olarak adlandırdığımı düşündüğümü uygulamalısınız. CLR, sonlandırıldıklarını garanti etmek için bu nesnelerin özel bir şekilde ele alınmasını sağlar (örneğin, düşük belleği işlemek için sonlandırma kodunu önceden kapatır)
adrianm

9

IDisposable arabirimini uygularlarsa, onları atmalısınız. Çöp toplayıcı gerisini halleder.

EDIT: en iyi usingtek kullanımlık öğelerle çalışırken komutu kullanmaktır :

using(var con = new SqlConnection("..")){ ...

5

Bir nesne uygular zaman IDisposablearamak gerekir Dispose(veya Closebazı durumlarda, bu sizin için Dispose arayacak).

Normalde nesneleri ayarlamak zorunda değilsiniz null, çünkü GC artık bir nesnenin kullanılmayacağını bilecektir.

Nesneleri olarak ayarladığımda bir istisna var null. Üzerinde çalışmam gereken bir sürü nesne (veritabanından) aldığımda ve bunları bir koleksiyonda (veya dizide) saklıyorum. "İş" tamamlandığında, nesneyi olarak ayarladım null, çünkü GC onunla çalışmayı bitirdiğimi bilmiyor.

Misal:

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

4

Normalde, alanları null olarak ayarlamanıza gerek yoktur. Ancak her zaman yönetilmeyen kaynakların elden çıkarılmasını tavsiye ederim.

Deneyimden ayrıca aşağıdakileri yapmanızı tavsiye ederim:

  • Artık ihtiyacınız yoksa etkinliklerden aboneliği iptal edin.
  • Temsilci veya ifade içeren herhangi bir alanı, artık gerekmiyorsa null değerine ayarlayın.

Yukarıdaki tavsiyelere uymamanın doğrudan sonucu olan sorunları bulmak için çok zor karşılaştım.

Bunu yapmak için iyi bir yer Dispose () 'dir, ancak daha erken genellikle daha iyidir.

Genel olarak, bir nesneye referans varsa, çöp toplayıcının (GC) bir nesnenin artık kullanımda olmadığını anlamak için birkaç nesil daha uzun sürebilir. Nesne bellekte kalırken.

Uygulamanızın beklediğinizden çok daha fazla bellek kullandığını bulana kadar bu bir sorun olmayabilir. Bu olduğunda, hangi nesnelerin temizlenmediğini görmek için bir bellek profili düzenleyicisini takın. Diğer nesnelere başvuran alanların boş değere ayarlanması ve bertaraftaki koleksiyonların temizlenmesi, GC'nin bellekten hangi nesneleri çıkarabileceğini anlamasına gerçekten yardımcı olabilir. GC, kullanılan belleği daha hızlı geri kazanarak uygulamanızı çok daha az aç ve hızlı hale getirir.


1
'Etkinlikler ve delegeler' hakkında ne demek istiyorsun - bunlarla ne temizlenmeli?
CJ7

@Craig - Cevabımı düzenledim. Umarım bu biraz açıklığa kavuşur.
Marnix van Valen

3

Her zaman dispose çağırın. Riske değmez. Büyük yönetilen kurumsal uygulamalara saygı gösterilmelidir. Hiçbir varsayım yapılamaz, yoksa sizi ısırmaya geri döner.

Lepie'yi dinleme.

Pek çok nesne aslında IDisposable'ı uygulamıyor, bu yüzden onlar için endişelenmenize gerek yok. Gerçekten kapsam dışına çıkarlarsa otomatik olarak serbest bırakılırlar. Ayrıca boş bir şey koymak zorunda kaldığım duruma hiç rastlamadım.

Olabilecek bir şey, birçok nesnenin açık tutulabilmesidir. Bu, uygulamanızın bellek kullanımını büyük ölçüde artırabilir. Bazen bunun gerçekte bir bellek sızıntısı olup olmadığını veya uygulamanızın çok fazla şey yapıp yapmadığını bulmak zordur.

Bellek profili araçları bu gibi şeylere yardımcı olabilir, ancak zor olabilir.

Buna ek olarak, her zaman gerekli olmayan etkinliklerden çıkın. Ayrıca WPF bağlanması ve kontrolleri konusunda dikkatli olun. Olağan bir durum değil, ancak altta yatan bir nesneye bağlı olan bir WPF kontrolüne sahip olduğum bir durumla karşılaştım. Altta yatan nesne büyüktü ve büyük miktarda bellek aldı. WPF denetimi yeni bir örnekle değiştiriliyordu ve eskisi hala bir nedenden dolayı hala takılıyordu. Bu büyük bir bellek sızıntısına neden oldu.

Arka sitede kod kötü yazılmış, ancak mesele kullanılmayan şeylerin kapsam dışında kalmasını sağlamak istediğinizdir. Bir bellek profiler ile bulmak uzun zaman aldı çünkü bellekte hangi şeylerin geçerli olduğunu ve ne olmaması gerektiğini bilmek zor.


2

Ben de cevaplamalıyım. JIT, değişken kullanımın statik analizinden kodla birlikte tablolar oluşturur. Bu tablo girdileri, geçerli yığın çerçevesinde "GC-Roots" dur. Talimat işaretçisi ilerledikçe, bu tablo girdileri geçersiz hale gelir ve çöp toplamaya hazır hale gelir. Bu nedenle: Kapsamlı bir değişkense, bunu null değerine ayarlamanız gerekmez - GC nesneyi toplar. Üye veya statik bir değişkense, bunu null değerine ayarlamanız gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.