Bertarafı çöp toplamadan ayırmak önemlidir. Tamamen ayrı şeylerdir, bir dakika içinde geleceğim ortak bir nokta ile.
Dispose
çöp toplama ve sonlandırma
Bir using
ifade yazdığınızda , bu sadece bir dene / nihayet bloğu için sözdizimsel şekerdir, böylece ifadenin Dispose
gövdesindeki kod using
bir istisna atsa bile çağrılır . O değil nesne blok sonunda toplanan çöp olduğu anlamına gelir.
Elden çıkarma, yönetilmeyen kaynaklarla (bellek dışı kaynaklar) ilgilidir. Bunlar, kullanıcı arabirimi tanıtıcıları, ağ bağlantıları, dosya tanıtıcıları vb. Olabilir. Bunlar sınırlı kaynaklardır, bu nedenle bunları mümkün olan en kısa sürede serbest bırakmak istersiniz. Sen uygulamalıdır IDisposable
senin tipin yönetilmeyen kaynak "sahibi olan" her ne zaman (genellikle bir üzerinden doğrudan ya IntPtr
(örneğin aracılığı ile dolaylı olarak) ya da Stream
bir SqlConnection
vb.)
Çöp toplamanın kendisi yalnızca bellekle ilgilidir - küçük bir değişiklik ile. Çöp toplayıcı artık referans verilemeyen nesneleri bulabilir ve onları serbest bırakabilir. Yine de her zaman çöp aramıyor - yalnızca ihtiyacı olduğunu algıladığında (örneğin, yığının bir "neslinin" hafızası biterse).
Büküm, sonuçlandırmadır . Çöp toplayıcı, artık erişilemeyen, ancak bir sonlandırıcıya sahip olan nesnelerin bir listesini tutar ( ~Foo()
biraz kafa karıştırıcı bir şekilde C # 'da olduğu gibi yazılır - bunlar C ++ yıkıcıları gibi değildir). Sonlandırıcıları bu nesneler üzerinde çalıştırır, sadece hafızaları boşaltılmadan önce fazladan temizleme yapmaları gerekmesi durumunda.
Sonlandırıcılar, türdeki kullanıcının düzenli bir şekilde atmayı unutması durumunda neredeyse her zaman kaynakları temizlemek için kullanılır. Bu nedenle, bir açarsanız FileStream
ancak Dispose
veya aramayı unutursanız Close
, sonlandırıcı sonunda temeldeki dosya tanıtıcısını sizin için serbest bırakır. İyi yazılmış bir programda, bence sonuçlandırıcılar neredeyse hiç ateş etmemelidir.
Bir değişkeni şuna ayarlamak null
Bir değişkeni ayarlamakla ilgili küçük bir nokta null
- çöp toplama uğruna bu neredeyse hiç gerekli değildir. Bazen bir üye değişkeni ise bunu yapmak isteyebilirsiniz, ancak deneyimlerime göre bir nesnenin "bir kısmına" artık ihtiyaç duyulmaması nadirdir. Yerel bir değişken olduğunda, JIT genellikle bir referansı bir daha ne zaman kullanmayacağınızı bilecek kadar akıllıdır (yayın modunda). Örneğin:
StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();
// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);
// These aren't helping at all!
x = null;
sb = null;
// Assume that x and sb aren't used here
Yerel bir değişkeni ayarlamanın faydalı olabileceği tek zaman null
, bir döngüde olduğunuz zamandır ve döngünün bazı dallarının değişkeni kullanması gerekir, ancak bilmediğiniz bir noktaya ulaştığınızı bilirsiniz. Örneğin:
SomeObject foo = new SomeObject();
for (int i=0; i < 100000; i++)
{
if (i == 5)
{
foo.DoSomething();
// We're not going to need it again, but the JIT
// wouldn't spot that
foo = null;
}
else
{
// Some other code
}
}
IDisposable / sonlandırıcıları uygulama
Öyleyse, kendi türleriniz sonuçlandırıcıları uygulamalı mı? Neredeyse kesinlikle değil. Yalnızca dolaylı olarak yönetilmeyen kaynakları tutuyorsanız (örneğin FileStream
, bir üye değişkeniniz varsa), kendi sonlandırıcınızı eklemenin bir faydası olmayacaktır: nesneniz olduğu zaman akış neredeyse kesinlikle çöp toplama için uygun olacaktır, bu nedenle yalnızca güvenebilirsiniz FileStream
bir sonlandırıcıya sahip olmak (gerekirse - başka bir şeye atıfta bulunabilir, vb.). Yönetilmeyen bir kaynağı "neredeyse" doğrudan tutmak istiyorsanız SafeHandle
, arkadaşınızdır - devam etmek biraz zaman alır, ancak bu, bir daha asla bir sonlandırıcı yazmaya neredeyse hiç gerek duymayacağınız anlamına gelir . Bir kaynak (an IntPtr
) üzerinde gerçekten doğrudan bir kontrolünüz varsa, genellikle bir sonlandırıcıya ihtiyacınız vardır veSafeHandle
yapabileceğin en kısa zamanda. (Orada iki bağlantı vardır - ideal olarak ikisini de okuyun.)
Joe Duffy'nin sonlandırıcılar ve IDisposable (birçok akıllı insanla birlikte yazılmıştır) hakkında okumaya değer çok uzun bir kılavuz seti vardır. Sınıflarınızı mühürlediğinizde, bunun hayatı çok daha kolay hale getireceğinin farkında olmak gerekir: Dispose
Yeni bir sanal Dispose(bool)
yöntemi çağırmak için geçersiz kılma modeli , sadece sınıfınız kalıtım için tasarlandığında geçerlidir.
Bu biraz saçma oldu, ancak lütfen biraz istediğin yerde açıklama iste :)