Aracılığıyla paylaş


Çöp toplamanın temelleri

Ortak dil çalışma zamanında (CLR), atık toplayıcı (GC) otomatik bellek yöneticisi görevi görür. Atık toplayıcı, bir uygulama için bellek ayırmayı ve serbest bırakma işlemini yönetir. Bu nedenle, yönetilen kodla çalışan geliştiricilerin bellek yönetimi görevlerini gerçekleştirmek için kod yazması gerekmez. Otomatik bellek yönetimi, bir nesneyi boşaltmayı unutma ve bellek sızıntısına neden olma veya zaten serbest bırakılmış bir nesne için boş belleğe erişmeye çalışma gibi yaygın sorunları ortadan kaldırabilir.

Bu makalede, çöp toplamanın temel kavramları açıklanmaktadır.

Sosyal haklar

Çöp toplayıcı aşağıdaki avantajları sağlar:

  • Geliştiricilerin belleği el ile serbest bırakmalarını sağlar.

  • Yönetilen yığındaki nesneleri verimli bir şekilde ayırır.

  • Artık kullanılmayan nesneleri geri alır, belleklerini temizler ve belleği gelecekteki ayırmalar için kullanılabilir durumda tutar. Yönetilen nesneler, başlangıç olarak otomatik olarak temiz içerik alır, böylece oluşturucularının her veri alanını başlatması gerekmez.

  • Bir nesnenin kendisi için başka bir nesne için ayrılan belleği kullanamamasını sağlayarak bellek güvenliği sağlar.

Belleğin temelleri

Aşağıdaki listede önemli CLR bellek kavramları özetlemektedir:

  • Her işlemin kendi ayrı sanal adres alanı vardır. Aynı bilgisayardaki tüm işlemler, varsa aynı fiziksel belleği ve sayfa dosyasını paylaşır.

  • Varsayılan olarak, 32 bit bilgisayarlarda her işlemin 2 GB kullanıcı modu sanal adres alanı vardır.

  • Uygulama geliştiricisi olarak yalnızca sanal adres alanıyla çalışırsınız ve fiziksel belleği hiçbir zaman doğrudan işlemezsiniz. Çöp toplayıcı, yönetilen yığında sanal belleği sizin için ayırır ve serbest bırakır.

    Yerel kod yazıyorsanız, sanal adres alanıyla çalışmak için Windows işlevlerini kullanırsınız. Bu işlevler yerel yığınlarda sizin için sanal bellek ayırır ve serbest bırakır.

  • Sanal bellek üç durumda olabilir:

    Durum Açıklama
    Ücretsiz Bellek bloğunun buna başvurusu yoktur ve ayırma için kullanılabilir.
    Ayrıldı Bellek bloğu kullanımınız için kullanılabilir ve başka bir ayırma isteği için kullanılamaz. Ancak, işlenmeden verileri bu bellek bloğunda depolayamazsınız.
    Kaydedilmiş Bellek bloğu fiziksel depolamaya atanır.
  • Sanal adres alanı parçalanabilir, yani adres alanında delik olarak bilinen boş bloklar vardır. Sanal bellek ayırma istendiğinde, sanal bellek yöneticisinin ayırma isteğini karşılamak için yeterince büyük tek bir boş blok bulması gerekir. 2 GB boş alanınız olsa bile, bu boş alanın tümü tek bir adres bloğunda olmadığı sürece 2 GB gerektiren ayırma başarısız olur.

  • Ayırmak için yeterli sanal adres alanı yoksa veya işlemek için fiziksel alan yoksa belleğiniz tükenebilir.

    Sayfa dosyası, fiziksel bellek baskısı (fiziksel bellek talebi) düşük olsa bile kullanılır. Fiziksel bellek baskısı ilk kez yüksek olduğunda, işletim sisteminin verileri depolamak için fiziksel bellekte yer açması gerekir ve fiziksel bellekteki bazı verileri sayfa dosyasına yedekler. Veriler gerekli olana kadar sayfalamaz, bu nedenle fiziksel bellek baskısının düşük olduğu durumlarda disk belleğiyle karşılaşabilirsiniz.

Bellek ayırma

Yeni bir işlem başlattığınızda, çalışma zamanı işlem için adres bölgesine bitişik bir adres alanı ayırır. Bu ayrılmış adres alanına yönetilen yığın denir. Yönetilen yığın, yığın içinde sıradaki nesnenin nereye ayrılacağını belirten bir işaretçi tutar. Başlangıçta, bu işaretçi yönetilen yığının taban adresi olarak ayarlanır. Tüm başvuru türleri yönetilen yığına ayrılır. Bir uygulama ilk referans türünü oluşturduğunda, türe yönelik bellek, yönetilen yığının taban adresinde ayrılır. Uygulama bir sonraki nesneyi oluşturduğunda, çalışma zamanı ilk nesnenin hemen ardından adres alanında bunun için bellek ayırır. Adres alanı kullanılabilir olduğu sürece çalışma zamanı yeni nesneler için bu şekilde alan ayırmaya devam eder.

Yönetilen yığından bellek ayırmak, yönetilmeyen bellek ayrımından daha hızlıdır. Çalışma zamanı işaretçiye değer ekleyerek bir nesne için bellek ayırdığından, yığından bellek ayırmak kadar hızlıdır. Ayrıca, ardışık olarak ayrılan yeni nesneler yönetilen yığında bitişik olarak depolandığından, bir uygulama nesnelere hızla erişebilir.

Bellek sürümü

Atık toplayıcısının optimizasyon altyapısı, yapılan ayrımlara göre bir toplama işlemini gerçekleştirmek için en iyi zamanı belirler. Atık toplayıcı bir toplama gerçekleştirdiğinde, uygulama tarafından artık kullanılmayan nesnelere ayrılan belleği serbest bırakır. Uygulamanın köklerini inceleyerek hangi nesnelerin artık kullanılmadığını belirler. Uygulamanın kökleri statik alanları, bir iş parçacığının yığınındaki yerel değişkenleri, CPU yazmaçlarını, GC tanıtıcılarını ve son haline getirme kuyruğuyu içerir. Her kök yönetilen yığındaki bir nesneye başvurur veya null olarak ayarlanır. Çöp toplayıcı, çalışma zamanının geri kalanında bu kökleri isteyebilir. Çöp toplayıcı, köklerden ulaşılabilen tüm nesneleri içeren bir grafik oluşturmak için bu listeyi kullanır.

Grafikte olmayan nesnelere uygulamanın köklerinden ulaşılamıyor. Çöp toplayıcı, ulaşılamayan nesneleri çöp olarak kabul eder ve onlar için ayrılan belleği serbest bırakır. Bir toplama sırasında, atık toplayıcı yönetilen yığını inceleyerek erişilemeyen nesneler tarafından kullanılan adres alanı bloklarını arar. Erişilemeyen nesneleri keşfettikçe, bir bellek kopyalama işleviyle bellekteki erişilebilir nesneleri sıkıştırır ve bu sayede, erişilemeyen nesnelere ayrılan adres alanlarını serbest bırakır. Erişilebilir nesneler için bellek sıkıştırıldıktan sonra atık toplayıcı gerekli işaretçi düzeltmelerini yaparak uygulamanın köklerinin nesnelerin yeni konumlarına işaret etmesini sağlar. Ayrıca yönetilen yığının işaretçisini erişilebilen son nesnenin sonuna konumlandırır.

Bellek, yalnızca bir koleksiyon çok sayıda ulaşılamayan nesne bulursa sıkıştırılır. Yönetilen yığındaki tüm nesneler bir koleksiyonda hayatta kalırsa bellek sıkıştırmaya gerek yoktur.

Performansı artırmak açısından, çalışma zamanı büyük nesneler için ayrı bir yığında bellek ayırır. Atık toplayıcı, büyük nesnelerin belleğini otomatik olarak serbest bırakır. Ancak, bellekteki büyük nesnelerin taşınmasını önlemek için bu bellek genellikle sıkıştırılmaz.

Çöp toplama koşulları

Aşağıdaki koşullardan biri doğru olduğunda çöp toplama gerçekleşir:

  • Sistemin fiziksel belleği düşük. Bellek boyutu, işletim sisteminden gelen düşük bellek bildirimi veya konak tarafından gösterildiği gibi düşük bellek tarafından algılanır.

  • Yönetilen yığında ayrılan nesneler tarafından kullanılan bellek kabul edilebilir eşiği aşıyor. İşlem çalıştırılırken bu eşik sürekli olarak ayarlanır.

  • GC.Collect yöntemi çağrılır. Hemen hemen tüm durumlarda, çöp toplayıcı sürekli çalıştığından bu yöntemi çağırmanız gerekmez. Bu yöntem öncelikli olarak benzersiz durumlar ve test için kullanılır.

Yönetilen yığın

CLR çöp toplayıcıyı başlatdıktan sonra, nesneleri depolamak ve yönetmek için bir bellek kesimi ayırır. Bu bellek, işletim sistemindeki yerel bir yığın yerine yönetilen yığın olarak adlandırılır.

Her yönetilen işlem için bir yönetilen yığın vardır. İşlemdeki tüm iş parçacıkları, aynı yığındaki nesneler için bellek ayırır.

Bellek ayırmak için, çöp toplayıcı Windows VirtualAlloc işlevini çağırır ve yönetilen uygulamalar için bir kerede bir bellek kesimi ayırır. Çöp toplayıcı ayrıca gerektiğinde segmentleri ayırır ve Windows VirtualFree işlevini çağırarak kesimleri işletim sistemine geri bırakır (herhangi bir nesne temizledikten sonra).

Önemli

Çöp toplayıcı tarafından ayrılan kesimlerin boyutu uygulamaya özgüdür ve düzenli güncelleştirmeler de dahil olmak üzere herhangi bir zamanda değiştirilebilir. Uygulamanız hiçbir zaman belirli bir segment boyutuyla ilgili varsayımlarda bulunmamalı veya segment ayırmaları için kullanılabilir bellek miktarını yapılandırmaya çalışmamalıdır.

Yığında ne kadar az nesne ayrılırsa, çöp toplayıcının yapması gereken iş de o kadar az olur. Nesneleri ayırdığınızda, yalnızca 15 bayta ihtiyacınız olduğunda 32 baytlık bir dizi ayırma gibi gereksinimlerinizi aşan yuvarlanmış değerler kullanmayın.

Bir çöp toplama tetiklendiğinde, çöp toplayıcı ölü nesneler tarafından işgal edilen belleği geri alır. Geri kazanma işlemi canlı nesneleri sıkıştırarak birlikte taşınmalarını sağlar ve ölü alan kaldırılır ve böylece yığın küçültilir. Bu işlem, birlikte ayrılan nesnelerin yerelliklerini korumak için yönetilen yığında birlikte kalmasını sağlar.

Atık toplamaların müdahaleciliği (sıklık ve süre), ayırma hacminin ve yönetilen yığındaki hayatta kalan bellek miktarının sonucudur.

Yığın, iki yığının birikmesi olarak kabul edilebilir: büyük nesne yığını ve küçük nesne yığını. Büyük nesne yığını, genellikle dizi olan 85.000 bayt ve daha büyük nesneler içerir. Bir örnek nesnesinin fazla büyük olması nadirdir.

İpucu

Nesnelerin büyük nesne yığınına gitmesi için eşik boyutunu yapılandırabilirsiniz.

Nesil

GC algoritması, dikkat edilmesi gereken bazı noktaları temel alır:

  • Yönetilen yığının bir bölümünün belleğini sıkıştırmak, yönetilen yığının tamamına göre daha hızlıdır.
  • Yeni nesnelerin kullanım ömrü daha kısadır ve eski nesneler daha uzun ömürlü olur.
  • Daha yeni nesneler birbiriyle ilişkili olma eğilimindedir ve uygulama tarafından aynı zamanda erişilir.

Çöp toplama öncelikli olarak kısa ömürlü nesnelerin geri kazanimiyla gerçekleşir. Çöp toplayıcının performansını iyileştirmek için yönetilen yığın, uzun ömürlü ve kısa ömürlü nesneleri ayrı ayrı işleyebilmesi için 0, 1 ve 2 olmak üzere üç nesile ayrılır. Çöp toplayıcı yeni nesneleri 0. nesilde depolar. Uygulama ömrünün başlarında oluşturulan ve toplamalardan sonra varlığını sürdüren nesneler yükseltilerek nesil 1 ve 2'de tutulur. Yönetilen yığının bir bölümünü yığının tamamına göre sıkıştırmak daha hızlı olduğundan, bu düzen çöp toplayıcının her toplama işlemi gerçekleştirişinde yönetilen yığının tamamının belleğini serbest bırakmak yerine belleği belirli bir nesilde serbest bırakmasına olanak tanır.

  • 0. Nesil: Bu nesil en genç nesildir ve kısa ömürlü nesneler içerir. Kısa ömürlü bir nesneye örnek olarak geçici değişken yer alır. Atık toplama en sık bu nesilde gerçekleşir.

    Yeni ayrılan nesneler yeni bir nesne nesli oluşturur ve örtük olarak 0. nesil koleksiyonlardır. Ancak, büyük nesnelerse, bazen 3. nesil olarak adlandırılan büyük nesne yığınına (LOH) gider. 3. nesil, mantıksal olarak 2. neslin bir parçası olarak toplanan fiziksel bir nesildir.

    Çoğu nesne, 0. nesilde atık toplama için geri kazanılır ve bir sonraki nesle kadar hayatta kalamaz.

    Bir uygulama, 0. nesil dolduğunda yeni bir nesne oluşturmaya çalışırsa, atık toplayıcı nesnenin adres alanını boşaltmak için bir koleksiyon gerçekleştirir. Atık toplayıcı, yönetilen yığındaki tüm nesneler yerine nesil 0'daki nesneleri inceleyerek başlar. Yalnızca 0. nesil bir koleksiyon genellikle uygulamanın yeni nesneler oluşturmaya devam edebilmesi için yeterli belleği geri alır.

  • 1. Nesil: Bu nesil kısa ömürlü nesneler içerir ve kısa ömürlü nesnelerle uzun ömürlü nesneler arasında arabellek görevi görür.

    Atık toplayıcı 0. nesil bir toplama işlemi gerçekleştirdikten sonra, erişilebilir nesnelerin belleğini sıkıştırıp 1. nesile yükseltiyor. Toplama işleminden sonra varlığını sürdüren nesneler daha uzun ömre sahip olmaya eğilimli olduklarından, bunları daha yüksek bir nesle yükseltmek mantıklıdır. Atık toplayıcının 1. nesil ve 2. nesildeki nesneleri 0. nesilden oluşan bir toplama işlemi her gerçekleştirişinde yeniden gözden geçirmesi gerekmez.

    0. nesil bir koleksiyon, uygulamanın yeni bir nesne oluşturması için yeterli belleği geri kazanmazsa, çöp toplayıcı 1. nesil ve sonra 2. nesilden oluşan bir toplama gerçekleştirebilir. Nesil 1'de toplama işlemlerinden sonra varlığına devam eden nesneler nesil 2'ye yükselir.

  • 2. Nesil: Bu nesil uzun ömürlü nesneler içerir. Uzun ömürlü bir nesneye örnek olarak, işlem süresi boyunca canlı olan statik veriler içeren bir sunucu uygulamasındaki bir nesne örnektir.

    2. nesildeki bir koleksiyonda hayatta kalan nesneler, gelecekteki bir koleksiyonda erişilemeyecekleri belirlenene kadar 2. nesilde kalır.

    Büyük nesne yığınındaki nesneler (bazen 3. nesil olarak da adlandırılır) 2. nesilde de toplanır.

Atık toplama işlemleri belirli nesillerde koşulların garanti edilmesiyle gerçekleşir. Bir nesli toplamak, bu nesildeki ve onun tüm genç nesillerindeki nesneleri toplamak anlamına gelir. 2. nesil çöp toplama, tüm nesillerdeki nesneleri (yönetilen yığındaki tüm nesneler) geri kazanacağından tam çöp toplama olarak da bilinir.

Hayatta kalma ve promosyonlar

Çöp toplamada geri kazanılmayan nesneler, hayatta kalanlar olarak bilinir ve yeni nesillere yükseltilir:

  • 0. nesil çöp toplama işleminden sonra kalan nesneler 1. nesil olarak yükseltilir.
  • 1. nesil çöp toplama işleminden sonra kalan nesneler 2. nesile yükseltilir.
  • 2. nesil çöp toplama işleminden sonra kalan nesneler 2. nesilde kalır.

Atık toplayıcı bir nesilde hayatta kalma oranının yüksek olduğunu algıladığında, bu nesil için ayırma eşiğini artırır. Sonraki koleksiyon, geri kazanılır belleğin önemli bir boyutunu alır. CLR sürekli olarak iki önceliği dengeler: çöp toplamayı geciktirerek ve çöp toplamanın çok sık çalışmasına izin vermeyerek uygulamanın çalışma kümesinin çok büyük bir boyuta sahip olmaması.

Kısa ömürlü nesiller ve segmentler

Nesil 0 ve 1'deki nesneler kısa ömürlü olduğundan, bu nesiller kısa ömürlü nesiller olarak bilinir.

Kısa ömürlü nesiller, kısa ömürlü segment olarak bilinen bellek kesiminde ayrılır. Çöp toplayıcı tarafından alınan her yeni kesim, yeni kısa ömürlü segment haline gelir ve nesil 0 çöp toplama işleminden sonra kalan nesneleri içerir. Eski kısa ömürlü segment, yeni nesil 2 segment haline gelir.

Kısa ömürlü kesimin boyutu, bir sistemin 32 bit mi yoksa 64 bit mi olduğuna ve çalıştırdığı çöp toplayıcı türüne (iş istasyonu veya sunucu GC) bağlı olarak değişir. Aşağıdaki tabloda kısa ömürlü segmentin varsayılan boyutları gösterilmektedir:

İş istasyonu/sunucu GC 32 bit 64 bit
İş İstasyonu GC 16MB 256 MB
Sunucu GC 64 MB 4 GB
4 mantıksal CPU ile > Sunucu GC 32MB 2 GB
8 mantıksal CPU ile > Sunucu GC 16MB 1 GB

Kısa ömürlü segment, 2. nesil nesneleri içerebilir. 2. nesil nesneler, işleminizin gerektirdiği ve belleğin izin verdiği kadar çok sayıda kesim kullanabilir.

Kısa ömürlü çöp toplamadan boşaltılan bellek miktarı kısa ömürlü kesimin boyutuyla sınırlıdır. Boşaltılan bellek miktarı, ölü nesnelerin kapladığı alanla orantılıdır.

Çöp toplama sırasında ne olur?

Çöp toplama aşağıdaki aşamalara sahiptir:

  • Tüm canlı nesnelerin listesini bulup oluşturan bir işaretleme aşaması.

  • Sıkıştırılacak nesnelere başvuruları güncelleştiren bir yeniden konumlandırma aşaması.

  • Ölü nesnelerin kapladığı alanı geri alan ve hayatta kalan nesneleri sıkıştıran bir sıkıştırma aşaması. Sıkıştırma aşaması, bir çöp toplama işleminden sonra kalan nesneleri segmentin eski ucuna taşır.

    2. nesil koleksiyonlar birden çok segmenti kaplayabildiğinden, 2. nesil olarak yükseltilen nesneler eski bir kesime taşınabilir. Hem 1. nesil hem de 2. nesil hayatta kalanlar, 2. nesil olarak yükseltildiği için farklı bir segmente taşınabilir.

    Normalde büyük nesne yığını (LOH) sıkıştırılmıyor çünkü büyük nesnelerin kopyalanması bir performans cezasına neden olur. Ancak, .NET Core ve .NET Framework 4.5.1 ve sonraki sürümlerinde, büyük nesne yığınını GCSettings.LargeObjectHeapCompactionMode isteğe bağlı olarak sıkıştırmak için özelliğini kullanabilirsiniz. Buna ek olarak, sabit sınır ayarlandığında LOH otomatik olarak sıkıştırılır ve aşağıdakilerden biri belirtilir:

Çöp toplayıcı, nesnelerin canlı olup olmadığını belirlemek için aşağıdaki bilgileri kullanır:

  • Yığın kökleri: Tam zamanında (JIT) derleyicisi ve yığın yürütücüsü tarafından sağlanan yığın değişkenleri. JIT iyileştirmeleri, yığın değişkenlerinin atık toplayıcıya bildirildiği kod bölgelerini uzatabilir veya kısaltabilir.

  • Çöp toplama tanıtıcıları: Yönetilen nesnelere işaret eden ve kullanıcı kodu veya ortak dil çalışma zamanı tarafından ayrılabilen tanıtıcılar.

  • Statik veriler: Uygulama etki alanlarındaki diğer nesnelere başvuruda bulunabilecek statik nesneler. Her uygulama etki alanı statik nesnelerini izler.

Çöp toplama başlamadan önce, çöp toplamayı tetikleyen iş parçacığı dışında tüm yönetilen iş parçacıkları askıya alınır.

Aşağıdaki çizimde, bir çöp toplamayı tetikleyen ve diğer iş parçacıklarının askıya alınmasına neden olan bir iş parçacığı gösterilmektedir:

Screenshot of how a thread triggers a Garbage Collection.

Yönetilmeyen kaynaklar

Uygulamanızın oluşturduğu nesnelerin çoğunda, gerekli bellek yönetimi görevlerini otomatik olarak gerçekleştirmek için çöp toplamaya güvenebilirsiniz. Ancak, yönetilmeyen kaynakların açıkça temizlenmesi gerekir. Yönetilmeyen kaynakların en yaygın türü, bir dosya işleyicisi, pencere işleyicisi veya ağ bağlantısı gibi işletim sistemi kaynağını sarmalayan bir nesnedir. Atık toplayıcı, yönetilmeyen bir kaynağı kapsülleyen yönetilen bir nesnenin ömrünü izleyebilir, ancak kaynağın nasıl temizlenmiş olduğu hakkında belirli bir bilgiye sahip değildir.

Yönetilmeyen bir kaynağı kapsülleyen bir nesne tanımladığınızda, genel Dispose bir yöntemde yönetilmeyen kaynağı temizlemek için gerekli kodu sağlamanız önerilir. Bir Dispose yöntem sağlayarak, nesnenizin kullanıcılarının nesneyle işi bittiğinde kaynağı açıkça serbest bırakmalarını sağlarsınız. Yönetilmeyen bir kaynağı kapsülleyen bir nesne kullandığınızda, gerektiğinde çağırdığınızdan Dispose emin olun.

Ayrıca, sizin türünüzdeki bir tüketicinin çağırmayı Disposeunutması durumunda yönetilmeyen kaynaklarınızın serbest bırakılması için bir yol da sağlamanız gerekir. Yönetilmeyen kaynağı sarmak için güvenli bir tanıtıcı kullanabilir veya yöntemini geçersiz kılabilirsiniz Object.Finalize() .

Yönetilmeyen kaynakları temizleme hakkında daha fazla bilgi için bkz . Yönetilmeyen kaynakları temizleme.

Ayrıca bkz.