Tüm GC uygulamalarını kullanmanın uygun bir yolu hakkında battaniye ifadeleri yapamazsınız . Onlar çılgınca değişir. Bu yüzden başlangıçta bahsettiğiniz .NET ile konuşacağım.
Herhangi bir mantık veya sebeple bunu yapmak için GC'nin davranışını oldukça yakından bilmeniz gerekir.
Koleksiyonda verebileceğim tek tavsiye şudur: Asla yapma.
GC'nin karmaşık ayrıntılarını gerçekten biliyorsanız, tavsiyeme gerek kalmaz, bu yüzden önemli olmaz. Zaten% 100 güvenle bilmiyorsanız o yardımcı ve çevrimiçi bakmak zorunda ve böyle bir cevap bulacaksınız: Sen GC.Collect çağırarak edilmemelidir veya alternatif: Sen nasıl GC eserlerin ayrıntılarını öğrenmek gitmeli içte ve dışta, ancak o zaman cevabı bileceksin .
O GC.Collect kullanmak için bazı mantıklı tek bir güvenli yer yoktur :
GC.Collect, işlerin zamanlamasını belirlemek için kullanabileceğiniz bir API'dir. Bir algoritmayı profillendirebilir, derhal başka bir algoritmayı profillendirebilir ve ardından birincisini algılayarak ilk algonun GC'sinin oluşmadığını bilirsiniz.
Bu tür bir profilleme, herhangi birisine manuel olarak toplama önerebileceğim tek zaman.
Yine de İçtiğimiz Örnek
Muhtemel bir kullanım durumu, eğer gerçekten büyük şeyler yüklerseniz, doğrudan Gen 2'ye gidecek olan Büyük Nesne Yığınına gireceklerdir, fakat yine de Gen 2, daha az sıklıkla topladığı için uzun ömürlü nesneler içindir. Herhangi bir nedenle kısa ömürlü nesneleri Gen 2'ye yüklediğinizi biliyorsanız , Gen 2'nizi daha küçük tutmak ve koleksiyonlarını daha hızlı tutmak için bunları daha çabuk temizleyebilirsiniz.
Bu, bulabileceğim en iyi örnek ve bu iyi değil - burada inşa ettiğiniz LOH baskısı daha sık koleksiyonlara neden olur ve koleksiyonlar olduğu kadar sıktır - olasılıklar LOH'yi olduğu gibi temizliyor olabilir geçici cisimlerle patlatırken hızlı. Ben sadece güvenmiyorum kendime uzak insanlar tarafından ayarlanan - GC kendisinden daha iyi bir toplama frekansı tahmin etmek çok benden daha akıllı
Öyleyse, .NET GC'deki bazı anlambilim ve mekanizmalardan bahsedelim ... veya ..
.NET GC hakkında bildiğim her şeyi düşünüyorum
Lütfen, burada hataları bulan herkes - beni düzeltir. GC'nin çoğunun kara büyü olduğu iyi biliniyor ve belirsiz olduğum detayları bırakmaya çalışırken, muhtemelen hala bazı şeyler yanlış.
Aşağıda kesin olarak bilmediğim çok daha fazla bilginin yanı sıra, emin olamadığım çok sayıda ayrıntı eksik. Bu bilgileri kullanmak kendi sorumluluğunuzdadır.
GC Kavramları
.NET GC tutarsız zamanlarda gerçekleşir, bu nedenle "deterministik olmayan" olarak adlandırılır, bu, belirli zamanlarda gerçekleşmesine güvenemeyeceğiniz anlamına gelir. Aynı zamanda bir kuşak çöp toplayıcısıdır, bu da nesnelerinizi kaç tane GC geçidi yaşadıklarına ayırdığı anlamına gelir.
Gen 0 yığınındaki nesneler 0 koleksiyonla yaşamıştır, bunlar yeni yapılmıştı, son zamanlarda bunlar hazır olmalarından bu yana hiçbir toplama gerçekleşmedi. Gen 1 yığınınızdaki nesneler bir koleksiyon geçidinde yaşamıştır ve aynı şekilde Gen 2 yığınınızdaki nesneler de 2 koleksiyon geçidinde yaşamıştır.
Şimdi bu belirli nesiller ve bölümleri buna göre nitelendirmesinin nedenini belirtmeye değer. .NET GC yalnızca bu üç nesli tanır, çünkü bu üç küme üzerinden geçen koleksiyonun tümü biraz farklıdır. Bazı nesneler koleksiyondan binlerce kez geçerek hayatta kalabilir. GC bunları yalnızca Gen 2 yığın bölümünün diğer tarafında bırakır, aslında Gen 44 olduklarından onları başka hiçbir yerde bölümlemenin bir anlamı yoktur; Üzerlerindeki koleksiyon geçişi Gen 2 yığınındaki her şey ile aynı.
Bu belirli nesiller için anlamsal amaçlar ve bunları onurlandıran mekanizmalar uygulandı ve bir dakika içinde bunlara ulaşacağım.
Koleksiyonda neler var
Bir GC koleksiyonu geçidinin temel konsepti, bu nesnelere hala canlı referanslar (GC kökleri) olup olmadığını görmek için bir yığın alanındaki her nesneyi kontrol etmesidir. Bir nesne için bir GC kökü bulunursa, bu şu anda kod yürütme kodunun hala o nesneye erişip kullanabileceği anlamına gelir, bu nedenle silinemez. Bununla birlikte, bir nesne için bir GC kökü bulunmazsa, bu, çalışan işlemin artık nesneye ihtiyacı olmadığı anlamına gelir, böylece yeni nesneler için belleği boşaltmak için onu kaldırabilir.
Şimdi bir grup nesneyi temizledikten ve bazılarını yalnız bıraktıktan sonra, talihsiz bir yan etki ortaya çıkacak: Ölülerin kaldırıldığı canlı nesneler arasında boş alan var. Yalnız bırakılırsa bu hafıza parçalanması yalnızca hafızayı boşa harcar, böylece koleksiyonlar genellikle "canlılık" denilen şeyi yaparlar, burada tüm canlı nesneleri sola alırlar ve yığın içinde bir araya getirirler, böylece boş hafıza Gen için yığının bir tarafında bitişik olur 0.
Şimdi 3 yığın bellek fikri göz önüne alındığında, hepsi yaşadıkları koleksiyon geçişlerinin sayısına göre bölümlere ayrılarak, bu bölümlerin neden var olduğu hakkında konuşalım.
Gen 0 Koleksiyonu
Gen 0 mutlak en yeni nesnelerdir, çok küçük olma eğilimindedir - bu yüzden güvenle sıkça toplayabilirsiniz . Sıklık, yığının küçük kalmasını ve koleksiyonların çok hızlı olmasını sağlar çünkü bu kadar küçük bir yığının üzerinde toplanırlar. Bu, aşağı yukarı iddia edilen bir buluşsal görüşe dayanmaktadır: Oluşturduğunuz , çok geçici olan geçici nesnelerin büyük bir kısmı , bu nedenle geçici olarak kullanıldıktan hemen sonra kullanılamaz veya referans alınmayacak ve bu nedenle toplanabilir.
Gen 1 Koleksiyonu
Gen 1, bu çok geçici nesneler kategorisine girmeyen nesneler olmakla birlikte hala kısa ömürlü olabilir, çünkü yaratılan nesnelerin büyük bir kısmı uzun süre kullanılmaz. Bu nedenle Gen 1 oldukça sık toplar, yine yığınını küçük tutar, böylece koleksiyonlar hızlı olur. Ancak, varsayım nesnelerinin daha az olduğu Gen 0'dan daha geçicidir, bu nedenle Gen 0'dan daha az toplanır.
Açıkça söyleyeceğim: Gen 0'ların koleksiyon geçişi ile Gen 1'leri arasında farklılık gösteren teknik mekanizmaları bilmiyorum, topladıkları sıklıktan başka hiç bir şey yoksa.
Gen 2 Koleksiyonu
Gen 2 şimdi tüm yığınların annesi olmalı, değil mi? Evet, bu az çok doğru. Tüm kalıcı nesnelerinizin yaşadığı yer - Main()
mesela hayatınızdaki nesne ve Main()
referansınız olan her şey, çünkü bunlar Main()
sürecinizin sonunda geri dönene kadar kökleşecektir .
Gen 2'nin temelde diğer nesillerin toplayamadığı her şey için bir kova olduğu düşünüldüğünde, nesneler büyük ölçüde kalıcıdır veya en azından uzun süre yaşadılar. Yani Gen 2’de olanların çok azını tanımak aslında toplanabilecek bir şey olacak, sık sık toplanması gerekmiyor. Bu, koleksiyonunun daha yavaş çalışmasını sağlar çünkü çok daha az sıklıkta çalışır. Yani bu temelde garip senaryolar için tüm ekstra davranışları takip ettikleri yer, çünkü onları yürütecek zamanları var.
Büyük Nesne Yığını
Gen 2'nin ekstra davranışlarına bir örnek, aynı zamanda Büyük Nesne Yığınında da toplama yaptığıdır. Şimdiye kadar tamamen Küçük Nesne Yığını hakkında konuşuyordum, ancak .NET çalışma zamanı, yukarıda sıkıştırma olarak adlandırdığım şey nedeniyle belirli boyutlardaki şeyleri ayrı bir yığına ayırıyor. Sıkıştırma, koleksiyonlar Küçük Nesne Yığınında bittiğinde hareket etmeyi gerektirir. Gen 1'de yaşayan 10 MB'lık bir nesne varsa, koleksiyondan sonra sıkıştırmayı tamamlaması çok daha uzun sürecek ve böylece Gen 1'in koleksiyonunu yavaşlatacak. Böylece 10 MB'lık nesne Büyük Nesne Yığına tahsis edilir ve çok nadir çalışan Gen 2 sırasında toplanır.
Sonlandırma
Başka bir örnek, sonlandırıcılar içeren nesnelerdir. Sonlandırıcıyı .NET'lerin GC (yönetilmeyen kaynaklar) kapsamı dışındaki kaynaklara başvuran bir nesneye koyuyorsunuz. Sonlandırıcı, GC'nin yönetilmeyen bir kaynak toplanmasını talep etmesinin tek yoludur - işleminizden sızmaması için yönetilmeyen kaynağın elle toplanması / kaldırılması / bırakılması için sonlandırıcınızı uygularsınız. GC nesnelerinizi sonlandırıcıyı gerçekleştirmeye başladığında, uygulamanız yönetilmeyen kaynağı temizler ve böylece GC'nin bir kaynak sızıntısı riski olmadan nesnenizi kaldırabilmesini sağlar.
Sonlandırıcıların bunu yaptığı mekanizma doğrudan bir sonlandırma kuyruğunda referans olarak alınmaktadır. Çalışma zamanı bir sonlandırıcıyla bir nesne tahsis ettiğinde, o nesneye sonlandırma sırasına bir işaretçi ekler ve nesnenizi yerine kilitler (sabitleme adı verilir), böylece sıkıştırma, sonlandırma sırası başvurusunu bozacak şekilde taşımaz. Toplama geçişleri gerçekleştikçe, sonunda nesneniz artık bir GC köküne sahip olmayacaktır, ancak sonlandırma toplanmadan önce gerçekleştirilmelidir. Öyleyse, nesne öldüğünde, koleksiyon sonlandırma kuyruğundan referansını hareket ettirecek ve "FReachable" kuyruğu olarak bilinen şeyin üzerine bir referans yerleştirecektir. Sonra koleksiyon devam ediyor. Gelecekte bir başka “deterministik olmayan” zamanda, Sonlandırıcı iş parçacığı olarak bilinen ayrı bir iş parçacığı, başvurulan nesnelerin her biri için sonlandırıcıları yürüten, Yenilebilir sıradan geçecektir. Bitirdikten sonra, FReachable kuyruğu boştur ve sonlandırmaya gerek duymadıklarını söyleyen her nesnenin başlığında bir miktar çevrilmiş (Bu bit elle de çevrilebilir)GC.SuppressFinalize
( Dispose()
yöntemlerde yaygın olan ), ayrıca nesnelerin kaldırıldığından şüpheleniyorum , ancak benden alıntı yapma. Bu nesnenin içinde bulunduğu yığınla ilgili bir sonraki koleksiyon sonunda toplanacak. Gen 0 koleksiyonları, bu sonlandırmaya ihtiyaç duyulan biti olan nesnelere bile dikkat etmiyor, köklerini kontrol etmeden otomatik olarak onları tanıtıyor. Gen 1'de sonlandırılması gereken köksüz bir nesne FReachable
kuyruğa atılacak, ancak koleksiyon bununla başka bir şey yapmaz, bu nedenle Gen 2'de yaşar. Bu şekilde, sonlandırıcıya sahip olan ve olmayan tüm nesneler GC.SuppressFinalize
Gen 2'de toplanacak.