Aracılığıyla paylaş


Atık toplama ve performans

Bu makalede çöp toplama ve bellek kullanımıyla ilgili sorunlar açıklanmaktadır. Yönetilen yığınla ilgili sorunları giderir ve atık toplamanın uygulamalarınız üzerindeki etkisini en aza indirmeyi açıklar. Her sorunun, sorunları araştırmak için kullanabileceğiniz yordamlara bağlantıları vardır.

Performans analizi araçları

Aşağıdaki bölümlerde bellek kullanımı ve çöp toplama sorunlarını araştırmak için kullanılabilecek araçlar açıklanmaktadır. Bu makalenin devamında sağlanan prosedürler bu araçlarla ilgilidir.

Bellek Performansı Sayaçları

Performans verilerini toplamak için performans sayaçlarını kullanabilirsiniz. Yönergeler için bkz . Çalışma Zamanı Profili Oluşturma. .NET'teki Performans Sayaçları'nda açıklandığı gibi performans sayaçlarının .NET CLR Bellek kategorisi, çöp toplayıcı hakkında bilgi sağlar.

SOS ile hata ayıklama

Yönetilen yığındaki nesneleri incelemek için Windows Hata Ayıklayıcısı'nı (WinDbg) kullanabilirsiniz.

WinDbg'yi yüklemek için Windows için Hata Ayıklama Araçlarını İndirme sayfasından Windows için Hata Ayıklama Araçları'nı yükleyin.

Atık Toplama ETW Olayları

Windows için olay izleme (ETW), .NET tarafından sağlanan profil oluşturma ve hata ayıklama desteğini tamamlayan bir izleme sistemidir. .NET Framework 4'ten başlayarak , atık toplama ETW olayları yönetilen yığını istatistiksel bir bakış açısından analiz etmek için yararlı bilgileri yakalar. Örneğin, GCStart_V1 bir çöp toplama işlemi gerçekleşmek üzereyken ortaya çıkan olay aşağıdaki bilgileri sağlar:

  • Hangi nesil nesneler toplanıyor?
  • Çöp toplamayı tetikleyen şey.
  • Atık toplama türü (eşzamanlı veya eşzamanlı değil).

ETW olay günlüğü verimlidir ve çöp toplamayla ilişkili performans sorunlarını maskelemeyecektir. Bir işlem, ETW olaylarıyla birlikte kendi olaylarını sağlayabilir. Kayıt altına alındığında, yığın sorunlarının nasıl ve ne zaman oluştuğunun belirlenmesi için hem uygulamanın olayları hem de çöp toplama olayları ilişkilendirilebilir. Örneğin, bir sunucu uygulaması istemci isteğinin başında ve sonunda olaylar sağlayabilir.

Profil Oluşturma API'si

Ortak dil çalışma zamanı (CLR) profil oluşturma arabirimleri, atık toplama sırasında etkilenen nesneler hakkında ayrıntılı bilgi sağlar. Çöp toplama başladığında ve sona erdiğinde profil oluşturucuya bildirim yapılabilir. Yönetilen yığındaki nesneler hakkında raporlar sağlayabilir ve her nesildeki nesnelerin tanımlanmasını da içerebilir. Daha fazla bilgi için bkz. Profil Oluşturma'ya Genel Bakış.

Profil oluşturucular kapsamlı bilgiler sağlayabilir. Ancak, karmaşık profil oluşturucular bir uygulamanın davranışını değiştirebilir.

Uygulama Etki Alanı Kaynak İzleme

.NET Framework 4'den başlayarak, Uygulama etki alanı kaynak izleme (ARM), konakların uygulama etki alanına göre CPU ve bellek kullanımını izlemesini sağlar. Daha fazla bilgi için bkz. Uygulama Etki Alanı Kaynak İzleme.

Performans sorunlarını giderme

İlk adım, sorunun aslında çöp toplama olup olmadığını belirlemektir. Bunun olduğunu belirlerseniz, sorunu gidermek için aşağıdaki listeden öğesini seçin.

Sorun: Bellek Yetersizliği İstisnası Oluştu

Yönetilen bir OutOfMemoryException hatasının atılması için iki geçerli durum vardır.

  • Sanal bellek tükeniyor.

    Atık toplayıcı, sistemdeki belleği önceden belirlenmiş boyutlarda bölümlerinde ayırır. Ayırma için ek bir kesim gerekiyorsa ancak işlemin sanal bellek alanında bitişik boş blok kalmadıysa, yönetilen yığın için ayırma başarısız olur.

  • Ayıracak yeterli fiziksel belleğe sahip değil.

Performans denetimleri
Bellek dışı özel durumun yönetilip yönetilmediğini belirleyin.
Ne kadar sanal belleğin ayrılabileceğini belirleyin.
Yeterli fiziksel bellek olup olmadığını belirleyin.

Özel durumun geçerli olmadığını belirlerseniz, aşağıdaki bilgilerle Microsoft Müşteri Hizmetleri ve Desteği'ne başvurun:

  • Yönetilen yetersiz bellek istisnasına sahip yığın.
  • Tam bellek dökümü.
  • Sanal veya fiziksel belleğin sorun olmadığını gösteren veriler de dahil olmak üzere, bunun meşru bir bellek dışı özel durum olmadığını kanıtlayan veriler.

Sorun: İşlem çok fazla bellek kullanıyor

Yaygın bir varsayım, Windows Görev Yöneticisi'nin Performans sekmesindeki bellek kullanımı görünümünün çok fazla bellek kullanıldığını gösterebileceğidir. Ancak, bu görüntü çalışma kümesiyle ilgili; sanal bellek kullanımı hakkında bilgi sağlamaz.

Sorunun yönetilen yığından kaynaklandığını belirlerseniz, tüm desenleri belirlemek için yönetilen yığını zaman içinde ölçmeniz gerekir.

Sorunun yönetilen yığından kaynaklanmadığını belirlerseniz yerel hata ayıklamayı kullanmanız gerekir.

Performans denetimleri
Ne kadar sanal belleğin ayrılabileceğini belirleyin.
Yönetilen yığının ne kadar bellek işlediğini belirleyin.
Yönetilen yığının ne kadar bellek ayırdığını belirleyin.
2. nesildeki büyük nesneleri belirleme.
Nesneler için referansları belirle.

Sorun: Çöp Toplayıcı nesneleri yeterince hızlı geri kazanmıyor

Nesneler çöp toplama için beklendiği gibi geri kazanılmıyor gibi göründüğünde, bu nesnelere yönelik güçlü başvurular olup olmadığını belirlemeniz gerekir.

Bu sorunla, ölü bir nesne içeren nesil için çöp toplama yapılmadıysa ve bu da ölü nesnenin sonlandırıcısının çalıştırılmadığını belirtiyorsa karşılaşabilirsiniz. Örneğin, tek iş parçacıklı bir apartman (STA) uygulaması çalıştırdığınızda ve sonlandırıcı kuyruğuna hizmet veren iş parçacığı ona çağrı yapamadığında bu mümkündür.

Performans denetimleri
Nesnelere referansları denetleyin.
Sonlandırıcının çalıştırılıp çalıştırılmadığını belirleyin.
Sonlandırılmayı bekleyen nesneler olup olmadığını belirleyin.

Sorun: Yönetilen Heap çok parçalanmış

Parçalanma düzeyi, oluşturma için ayrılan toplam bellek üzerindeki boş alan oranı olarak hesaplanır. 2. nesil için kabul edilebilir bir parçalanma düzeyi en fazla 20%. 2. nesil çok büyük olabileceğinden parçalanma oranı mutlak değerden daha önemlidir.

0. nesilde çok fazla boş alan olması sorun oluşturmaz çünkü bu, yeni nesnelerin ayrıldığı nesildir.

Parçalanma her zaman büyük nesne yığınında oluşur çünkü sıkıştırılmaz. Bitişik olan boş nesneler, büyük nesne ayırma isteklerini karşılamak için doğal olarak tek bir alana daraltılır.

Parçalanma, 1. nesil ve 2. nesillerde sorun haline gelebilir. Bu nesiller bir çöp toplama işleminden sonra büyük miktarda boş alana sahipse, uygulamanın nesne kullanımının değiştirilmesi gerekebilir ve uzun süreli nesnelerin ömrünü yeniden değerlendirmeyi düşünmelisiniz.

Nesnelerin aşırı sabitlenmeleri parçalanmayı artırabilir. Parçalanma yüksekse, çok fazla nesne sabitlenmiş olabilir.

Sanal belleğin parçalanması çöp toplayıcının kesim eklemesini engelliyorsa, bunun nedenleri şunlardan biri olabilir:

  • Birçok küçük derlemenin sık sık yüklenmesi ve boşaltılması.

  • Yönetilmeyen kodla birlikte çalışırken COM nesnelerine çok fazla referans tutma.

  • Büyük nesne yığınının yığın kesimlerini sık sık ayırıp boşaltmasına neden olan büyük geçici nesneler oluşturulması.

    Bir uygulama, CLR'yi çalıştırırken çöp toplayıcının bölümlerini tutmasını isteyebilir. Bu, segment ayırma sıklığını azaltır. Bu, STARTUP_FLAGS Numaralandırmasında STARTUP_HOARD_GC_VM bayrağı kullanılarak gerçekleştirilir.

Performans denetimleri
Yönetilen yığındaki boş alan miktarını belirleyin.
Sabitlenmiş nesnelerin sayısını belirleyin.

Parçalanmanın meşru bir nedeni olmadığını düşünüyorsanız Microsoft Müşteri Hizmetleri ve Desteği'ne başvurun.

Sorun: Çöp Toplama Duraklamaları Çok Uzun

Atık toplama yumuşak gerçek zamanlı olarak çalışır, bu nedenle bir uygulamanın bazı duraklamaları tolere edebilmesi gerekir. Yumuşak gerçek zamanlı için bir ölçüt, işlemlerin 95% zamanında bitmesi gerektiğidir.

Eşzamanlı çöp toplamada, yönetilen iş parçacıklarının bir toplama sırasında çalışmasına izin verilir, bu da duraklamaların çok az olduğu anlamına gelir.

Kısa ömürlü çöp toplama (0 ve 1 nesilleri) yalnızca birkaç milisaniye sürer, bu nedenle duraklamaların azaltılması genellikle mümkün değildir. Ancak, bir uygulamanın ayırma isteklerinin desenini değiştirerek 2. nesil koleksiyonlardaki duraklamaları azaltabilirsiniz.

Daha doğru bir diğer yöntem de atık toplama ETW olaylarını kullanmaktır. Bir olay dizisi için zaman damgası farklarını ekleyerek koleksiyonların zamanlamalarını bulabilirsiniz. Tüm koleksiyon dizisi yürütme altyapısının askıya alınmasını, çöp toplamanın kendisini ve yürütme altyapısının yeniden başlatılmasını içerir.

Bir sunucunun 2. nesil bir koleksiyona sahip olup olmadığını ve istekleri başka bir sunucuya yeniden yönlendirmenin duraklamalarla ilgili sorunları kolaylaştırıp kolaylaştırmayacağını belirlemek için Çöp Toplama Bildirimleri'ni kullanabilirsiniz.

Performans denetimleri
Bir çöp toplamadaki sürenin uzunluğunu belirleyin.
Çöp toplamaya neyin neden olduğunu belirleyin.

Sorun: 0. Nesil Çok Büyük

Özellikle iş istasyonu çöp toplama yerine sunucu çöp toplama kullandığınızda, 0. nesil büyük olasılıkla 64 bit sistem üzerinde daha fazla sayıda nesneye sahip olabilir. Bunun nedeni, 0. nesil çöp toplamayı tetikleme eşiğinin bu ortamlarda daha yüksek olması ve 0. nesil koleksiyonların çok daha büyüyebileceğidir. Bir uygulama çöp toplama tetiklenmeden önce daha fazla bellek ayırdığında performans iyileştirilir.

Sorun: Çöp Toplama Sırasında CPU Kullanımı Çok Yüksek

Atık toplama sırasında CPU kullanımı yüksek olacaktır. Bir çöp toplama işleminde önemli miktarda işlem süresi harcanırsa, koleksiyon sayısı çok sıktır veya koleksiyon çok uzun sürer. Yönetilen yığındaki nesnelerin artan ayırma oranı, atık toplama işleminin daha sık gerçekleşmesine neden olur. Ayırma oranının azaltılması, çöp toplama sıklığını azaltır.

Performans sayacını Allocated Bytes/second kullanarak ayırma oranlarını izleyebilirsiniz. Daha fazla bilgi için bkz. .NET'te Performans Sayaçları.

Bir koleksiyonun süresi birincil olarak ayırmadan sonra hayatta kalan nesne sayısının bir faktörüdür. Çok sayıda nesne toplanmaya devam ederse, atık toplayıcının büyük miktarda bellekten geçmesi gerekir. Hayatta kalanları sıkıştırmak zaman alır. Bir koleksiyon sırasında kaç nesnenin işlendiğini belirlemek için, belirtilen bir nesil için çöp toplama işleminin sonunda hata ayıklayıcıda bir kesme noktası ayarlayın.

Performans denetimleri
Atık toplamadan kaynaklanan yüksek CPU kullanımı olup olmadığını belirleyin.
Çöp toplama işleminin sonunda bir kesme noktası ayarlayın.

Sorun giderme yönergeleri

Bu bölümde, araştırmalarınıza başlarken göz önünde bulundurmanız gereken yönergeler açıklanmaktadır.

İş İstasyonu veya Sunucu Çöp Toplama

Doğru çöp toplama türünü kullanıp kullanmayabileceğinizi belirleyin. Uygulamanız birden fazla iş parçacığı ve nesne örneği kullanıyorsa, iş istasyonu çöp toplama yerine sunucu çöp toplamayı tercih edin. Sunucu çöp toplama birden çok iş parçacığında çalışırken, iş istasyonu çöp toplama işlemi bir uygulamanın birden çok örneğinin kendi çöp toplama iş parçacıklarını çalıştırmasını ve CPU süresi için birbirleriyle rekabet etmesini gerektirir.

Düşük yükte olan ve arka planda nadiren görev gerçekleştiren, örneğin bir hizmet gibi bir uygulama, eş zamanlı çöp toplama devre dışı bırakıldığında iş istasyonu çöp toplamasını kullanabilir.

Yönetilen Yığın Boyutu Ne Zaman Ölçülmeli?

Profil oluşturucu kullanmadığınız sürece performans sorunlarını etkili bir şekilde tanılamak için tutarlı bir ölçüm düzeni oluşturmanız gerekir. Bir zamanlama oluşturmak için aşağıdaki noktaları göz önünde bulundurun:

  • 2. nesil çöp toplama işleminden sonra ölçüm yaparsanız, yönetilen yığının tamamı çöp (ölü nesneler) içermez.
  • 0. nesil çöp toplama işleminden hemen sonra ölçüm yaparsanız, 1. ve 2. nesillerdeki nesneler henüz toplanmaz.
  • Bir çöp toplamadan hemen önce ölçüm yaparsanız, çöp toplama başlamadan önce mümkün olduğunca fazla ayırmayı ölçersiniz.
  • Atık toplayıcı veri yapıları geçiş için geçerli bir durumda olmadığından ve size tam sonuçları veremediğinden, atık toplama sırasında ölçüm yapmak sorunludur. Bu tasarım gereğidir.
  • Eşzamanlı çöp toplama ile birlikte iş istasyonu çöp toplama kullanırken, geri kazanılan nesneler sıkıştırılmaz, bu nedenle yığın boyutu aynı kalabilir veya daha büyük olabilir (parçalanma, daha büyük görünmesine neden olabilir).
  • Fiziksel bellek yükü çok yüksek olduğunda 2. nesildeki eşzamanlı çöp toplama işlemi gecikir.

Aşağıdaki yordamda, yönetilen yığını ölçebilmeniz için kesme noktasının nasıl ayarlanacağı açıklanmaktadır.

Çöp toplamanın sonunda bir kesme noktası ayarlamak için

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg'de aşağıdaki komutu girin:

    bp mscorwks!WKS::GCHeap::RestartEE "j (dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2) 'kb';'g'"

    İstenen nesile ayarlayın GcCondemnedGeneration. Bu komut özel simgeler gerektirir.

    Bu komut, 2. nesil nesneler atık toplama için geri kazanıldıktan sonra yürütülürse RestartEE bir kesmeye zorlar.

    Sunucu çöp toplama sırasında, yalnızca bir işlem birimi RestartEE çağırır, bu nedenle kesme noktası 2. nesil çöp toplama sırasında yalnızca bir kez oluşacaktır.

Performans denetimi yordamları

Bu bölümde, performans sorununuzun nedenini yalıtmak için aşağıdaki yordamlar açıklanmaktadır:

Sorunun çöp toplamadan kaynaklanıp kaynak olmadığını belirlemek için

  • Aşağıdaki iki bellek performansı sayacını inceleyin:

    • % GC'de Zaman. Son çöp toplama döngüsünden sonra bir çöp toplama işlemi gerçekleştirmek için harcanan geçen sürenin yüzdesini görüntüler. Çöp toplayıcının yönetilen yığın alanını kullanılabilir hale getirmek için çok fazla zaman harcayıp harcamadığını belirlemek için bu sayacı kullanın. Çöp toplamada harcanan süre görece düşükse, bu yönetilen yığının dışında bir kaynak sorununa işaret edebilir. Eşzamanlı veya arka plan çöp toplama söz konusu olduğunda bu sayaç doğru olmayabilir.

    • # Toplam işlenen Bayt sayısı. Çöp toplayıcı tarafından şu anda ayrılan sanal bellek miktarını görüntüler. Çöp toplayıcı tarafından tüketilen belleğin uygulamanızın kullandığı belleğin aşırı bir bölümü olup olmadığını belirlemek için bu sayacı kullanın.

    Bellek performans sayaçlarının çoğu her çöp toplama işleminin sonunda güncelleştirilir. Bu nedenle, bunlar hakkında bilgi almak istediğiniz geçerli koşulları yansıtmayabilir.

Bellek dışı özel durumun yönetilip yönetilmediğini belirlemek için

  1. SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg veya Visual Studio hata ayıklayıcısına yazdırma özel durumu (pe) komutunu girin:

    !pe

    Özel durum yönetiliyorsa, OutOfMemoryException aşağıdaki örnekte gösterildiği gibi özel durum türü olarak görüntülenir.

    Exception object: 39594518
    Exception type: System.OutOfMemoryException
    Message: <none>
    InnerException: <none>
    StackTrace (generated):
    
  2. Çıkış bir özel durum belirtmezse, bellek dışı özel durumun hangi iş parçacığından olduğunu belirlemeniz gerekir. Tüm iş parçacıklarını çağrı yığınlarıyla göstermek için hata ayıklayıcıya aşağıdaki komutu girin:

    ~\*kb

    İstisna çağrılarına sahip olan yığını içeren iş parçacığı RaiseTheException argümanıyla belirtilir. Bu yönetilen özel durum nesnesidir.

    28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0
    
  3. İç içe özel durumların dökümünü almak için aşağıdaki komutu kullanabilirsiniz.

    !pe -nested

    Özel durum bulamazsanız, bellek dışı özel durum yönetilmeyen koddan kaynaklanır.

Ne kadar sanal belleğin ayrılabileceğini belirlemek için

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg'de, en büyük boş bölgeyi almak için aşağıdaki komutu girin:

    !address -summary

    En büyük ücretsiz bölge aşağıdaki çıkışta gösterildiği gibi görüntülenir.

    Largest free region: Base 54000000 - Size 0003A980
    

    Bu örnekte, en büyük boş bölgenin boyutu yaklaşık 24000 KB'dir (onaltılık olarak 3A980). Bu bölge, çöp toplayıcının bir segment için ihtiyaç duyduğundan çok daha küçüktür.

    -veya-

  • vmstat komutunu kullanın:

    !vmstat

    En büyük boş bölge, aşağıdaki çıkışta gösterildiği gibi MAXIMUM sütunundaki en büyük değerdir.

    TYPE        MINIMUM   MAXIMUM     AVERAGE   BLK COUNT   TOTAL
    ~~~~        ~~~~~~~   ~~~~~~~     ~~~~~~~   ~~~~~~~~~~  ~~~~
    Free:
    Small       8K        64K         46K       36          1,671K
    Medium      80K       864K        349K      3           1,047K
    Large       1,384K    1,278,848K  151,834K  12          1,822,015K
    Summary     8K        1,278,848K  35,779K   51          1,824,735K
    

Yeterli fiziksel bellek olup olmadığını belirlemek için

  1. Windows Görev Yöneticisi'ni başlatın.

  2. Performance sekmesinde, taahhüt edilen değere bakın. (Windows 7'de Commit (KB) öğesine System group içinde bakın.)

    Total değerine yakınsaLimit, fiziksel belleğiniz azalıyordur.

Yönetilen yığının ne kadar bellek taahhüt ettiğini belirlemek için

  • Yönetilen yığının # Total committed bytes işlediği bayt sayısını almak için bellek performans sayacını kullanın. Çöp toplayıcı, bir segmentteki parçaları gerektiği gibi tahsis eder, hepsini aynı anda yapmaz.

    Uyarı

    Yönetilen yığın tarafından gerçek bellek kullanımını temsil etmediğinden performans sayacını kullanmayın # Bytes in all Heaps . Bir neslin boyutu bu değere dahil edilir ve aslında eşik boyutudur, yani nesil nesnelerle doluysa çöp toplamaya neden olan boyuttur. Bu nedenle, bu değer genellikle sıfırdır.

Yönetilen yığının ne kadar bellek ayırdığını belirlemek için

  • Bellek performans sayacını # Total reserved bytes kullanın.

    Çöp toplayıcı bellek segmentlerini ayırır ve bir segmentin nereden başlayacağını eeheap komutunu kullanarak belirleyebilirsiniz.

    Önemli

    Çöp toplayıcının her segment için ayırabileceği bellek miktarını belirleyebilirsiniz ancak kesim 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.

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg veya Visual Studio hata ayıklayıcısına aşağıdaki komutu girin:

    !eeheap -gc

    Sonuç aşağıdaki gibidir.

    Number of GC Heaps: 2
    ------------------------------
    Heap 0 (002db550)
    generation 0 starts at 0x02abe29c
    generation 1 starts at 0x02abdd08
    generation 2 starts at 0x02ab0038
    ephemeral segment allocation context: none
      segment    begin allocated     size
    02ab0000 02ab0038  02aceff4 0x0001efbc(126908)
    Large object heap starts at 0x0aab0038
      segment    begin allocated     size
    0aab0000 0aab0038  0aab2278 0x00002240(8768)
    Heap Size   0x211fc(135676)
    ------------------------------
    Heap 1 (002dc958)
    generation 0 starts at 0x06ab1bd8
    generation 1 starts at 0x06ab1bcc
    generation 2 starts at 0x06ab0038
    ephemeral segment allocation context: none
      segment    begin allocated     size
    06ab0000 06ab0038  06ab3be4 0x00003bac(15276)
    Large object heap starts at 0x0cab0038
      segment    begin allocated     size
    0cab0000 0cab0038  0cab0048 0x00000010(16)
    Heap Size    0x3bbc(15292)
    ------------------------------
    GC Heap Size   0x24db8(150968)
    

    "segment" tarafından belirtilen adresler, segmentlerin başlangıç adresleridir.

2. nesildeki büyük nesneleri belirlemek için

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg veya Visual Studio hata ayıklayıcısına aşağıdaki komutu girin:

    !dumpheap –stat

    Yönetilen yığın büyükse, dumpheap'ün tamamlanması biraz zaman alabilir.

    En çok alan kullanan nesneleri listelediklerinden, çıkışın son birkaç satırıyla çözümlemeye başlayabilirsiniz. Örneğin:

    2c6108d4   173712     14591808 DevExpress.XtraGrid.Views.Grid.ViewInfo.GridCellInfo
    00155f80      533     15216804      Free
    7a747c78   791070     15821400 System.Collections.Specialized.ListDictionary+DictionaryNode
    7a747bac   700930     19626040 System.Collections.Specialized.ListDictionary
    2c64e36c    78644     20762016 DevExpress.XtraEditors.ViewInfo.TextEditViewInfo
    79124228   121143     29064120 System.Object[]
    035f0ee4    81626     35588936 Toolkit.TlkOrder
    00fcae40     6193     44911636 WaveBasedStrategy.Tick_Snap[]
    791242ec    40182     90664128 System.Collections.Hashtable+bucket[]
    790fa3e0  3154024    137881448 System.String
    Total 8454945 objects
    

    Listelenen son nesne bir dizedir ve en fazla alanı kaplar. Dize nesnelerinizin nasıl iyileştirilebileceğini görmek için uygulamanızı inceleyebilirsiniz. 150 ile 200 bayt arasındaki dizeleri görmek için aşağıdakileri girin:

    !dumpheap -type System.String -min 150 -max 200

    Sonuçların bir örneği aşağıda verilmiştir.

    Address  MT           Size  Gen
    1875d2c0 790fa3e0      152    2 System.String HighlightNullStyle_Blotter_PendingOrder-11_Blotter_PendingOrder-11
    …
    

    Kimlik için dize yerine tamsayı kullanmak daha verimli olabilir. Aynı dize binlerce kez yineleniyorsa, dize havuzlama kullanmayı göz önünde bulundurun. Dize havuzu hakkında daha fazla bilgi almak için String.Intern yönteminin referans konusuna bakın.

Nesnelere yapılan atıfları belirlemek için

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg'de, nesnelere yapılan başvuruları listelemek için aşağıdaki komutu girin:

    !gcroot

    -veya-

  • Belirli bir nesneye ait referansları belirlemek için adresi ekleyin:

    !gcroot 1c37b2ac

    Yığınlarda bulunan kökler yanlış pozitifler olabilir. Daha fazla bilgi edinmek için !help gcroot komutunu kullanın.

    ebx:Root:19011c5c(System.Windows.Forms.Application+ThreadContext)->
    19010b78(DemoApp.FormDemoApp)->
    19011158(System.Windows.Forms.PropertyStore)->
    … [omitted]
    1c3745ec(System.Data.DataTable)->
    1c3747a8(System.Data.DataColumnCollection)->
    1c3747f8(System.Collections.Hashtable)->
    1c376590(System.Collections.Hashtable+bucket[])->
    1c376c98(System.Data.DataColumn)->
    1c37b270(System.Data.Common.DoubleStorage)->
    1c37b2ac(System.Double[])
    Scan Thread 0 OSTHread 99c
    Scan Thread 6 OSTHread 484
    

    Komutun gcroot tamamlanması uzun sürebilir. Çöp toplama tarafından geri kazanılmayan tüm nesneler canlı bir nesnedir. Başka bir deyişle, bir kök doğrudan veya dolaylı olarak nesneyi tutuyor, bu nedenle gcroot nesneye yol bilgisi döndürmelidir. Döndürülen grafikleri incelemeniz ve bu nesnelere neden hala başvurıldığını görmeniz gerekir.

Sonlandırıcının çalıştırılıp çalıştırılmadığını belirlemek için

  • Aşağıdaki kodu içeren bir test programı çalıştırın:

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    

    Test sorunu çözerse, bu, bu nesnelerin finalizörleri askıya alındığı için çöp toplayıcının nesneleri geri kazanamadığı anlamına gelir. GC.WaitForPendingFinalizers yöntemi, sonlandırıcıların görevlerini tamamlamasına olanak tanır ve sorunu çözer.

Sonlandırılmayı bekleyen nesneler olup olmadığını belirlemek için

  1. SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg veya Visual Studio hata ayıklayıcısına aşağıdaki komutu girin:

    !finalizequeue

    Sonlandırma için hazır olan nesne sayısına bakın. Sayı yüksekse, bu sonlandırıcıların neden hiç ilerleme göstermediğini veya yeterince hızlı ilerleyemediğini incelemeniz gerekir.

  2. İş parçacıklarının çıktısını almak için aşağıdaki komutu girin:

    !threads -special

    Bu komut aşağıdaki gibi bir çıkış sağlar.

       OSID     Special thread type
    2    cd0    DbgHelper
    3    c18    Finalizer
    4    df0    GC SuspendEE
    

    Sonlandırıcı iş parçacığı, varsa şu anda hangi sonlandırıcının çalıştırıldığını gösterir. Sonlandırıcı iş parçacığı herhangi bir sonlandırıcı çalıştırmadığında, görevini yapması için bir olayın ona sinyal vermesini bekler. Çoğu zaman sonlandırıcı iş parçacığını bu durumda görürsünüz çünkü THREAD_HIGHEST_PRIORITY ile çalışır ve varsa sonlandırıcıları çok hızlı bir şekilde çalıştırmayı tamamlaması gerekir.

Yönetilen yığındaki boş alan miktarını belirlemek için

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg veya Visual Studio hata ayıklayıcısına aşağıdaki komutu girin:

    !dumpheap -type Free -stat

    Bu komut, aşağıdaki örnekte gösterildiği gibi yönetilen yığındaki tüm boş nesnelerin toplam boyutunu görüntüler.

    total 230 objects
    Statistics:
          MT    Count    TotalSize Class Name
    00152b18      230     40958584      Free
    Total 230 objects
    
  • 0. nesildeki boş alanı belirlemek için, nesillere göre bellek tüketimi bilgileri için aşağıdaki komutu girin:

    !eeheap -gc

    Bu komut çıktıyı aşağıdakine benzer şekilde görüntüler. Son satır geçici segmenti gösterir.

    Heap 0 (0015ad08)
    generation 0 starts at 0x49521f8c
    generation 1 starts at 0x494d7f64
    generation 2 starts at 0x007f0038
    ephemeral segment allocation context: none
    segment  begin     allocated  size
    00178250 7a80d84c  7a82f1cc   0x00021980(137600)
    00161918 78c50e40  78c7056c   0x0001f72c(128812)
    007f0000 007f0038  047eed28   0x03ffecf0(67103984)
    3a120000 3a120038  3a3e84f8   0x002c84c0(2917568)
    46120000 46120038  49e05d04   0x03ce5ccc(63855820)
    
  • 0. nesil tarafından kullanılan alanı hesaplayın:

    ? 49e05d04-0x49521f8c

    Sonuç aşağıdaki gibidir. 0. nesil yaklaşık 9 MB'tır.

    Evaluate expression: 9321848 = 008e3d78
    
  • Aşağıdaki komut, nesil 0 aralığındaki boş alanı döküm eder:

    !dumpheap -type Free -stat 0x49521f8c 49e05d04

    Sonuç aşağıdaki gibidir.

    ------------------------------
    Heap 0
    total 409 objects
    ------------------------------
    Heap 1
    total 0 objects
    ------------------------------
    Heap 2
    total 0 objects
    ------------------------------
    Heap 3
    total 0 objects
    ------------------------------
    total 409 objects
    Statistics:
          MT    Count TotalSize Class Name
    0015a498      409   7296540      Free
    Total 409 objects
    

    Bu çıkış, yığının 0. nesil bölümünün nesneler için 9 MB alan kullandığını ve 7 MB boşluğa sahip olduğunu gösterir. Bu analiz, 0. neslin parçalanmayla ne ölçüde katkıda bulunduğu gösterir. Bu yığın kullanım miktarı, uzun vadeli nesnelerin parçalanmaya neden olması nedeniyle toplam miktardan düşülmelidir.

Sabitlenmiş öğe sayısını belirlemek için

  • SOS hata ayıklayıcısı uzantısının yüklü olduğu WinDbg veya Visual Studio hata ayıklayıcısına aşağıdaki komutu girin:

    !gchandles

    Görüntülenen istatistikler, sabitlenmiş tanıtıcıların sayısını içerir, aşağıdaki örnekte gösterildiği gibi.

    GC Handle Statistics:
    Strong Handles:      29
    Pinned Handles:      10
    

Çöp toplamadaki süreyi belirlemek için

  • Bellek performans sayacını % Time in GC inceleyin.

    Değer, örnek bir aralık süresi kullanılarak hesaplanır. Sayaçlar her çöp toplama işleminin sonunda güncelleştirildiğinden, aralık boyunca hiçbir koleksiyon gerçekleşmediyse geçerli örnek önceki örnekle aynı değere sahip olur.

    Toplama süresi, örnek aralık süresi ile yüzde değeri çarpılarak elde edilir.

    Aşağıdaki veriler, 8 saniyelik bir çalışma için iki saniyelik dört örnekleme aralığını göstermektedir. Gen0, Gen1ve Gen2 sütunları, bu nesil için aralığın sonuna kadar tamamlanan toplam çöp toplama sayısını gösterir.

    Interval    Gen0    Gen1    Gen2    % Time in GC
            1       9       3       1              10
            2      10       3       1               1
            3      11       3       1               3
            4      11       3       1               3
    

    Bu bilgiler çöp toplama işleminin ne zaman gerçekleştiğini göstermez, ancak belirli bir zaman aralığında oluşan çöp toplamalarının sayısını belirleyebilirsiniz. En kötü durum varsayarsak, onuncu nesil 0 çöp toplama işlemi ikinci aralığın başında, on birinci nesil 0 çöp toplama işlemi ise üçüncü aralığın sonunda tamamlanmıştır. Onuncu ve on birinci çöp toplamanın sonu arasındaki süre yaklaşık 2 saniyedir ve performans sayacı 3%gösterir, bu nedenle on birinci nesil 0 çöp toplama süresi (2 saniye * 3% = 60ms) olur.

    Sonraki örnekte beş aralık vardır.

    Interval    Gen0    Gen1    Gen2     % Time in GC
            1       9       3       1                3
            2      10       3       1                1
            3      11       4       1                1
            4      11       4       1                1
            5      11       4       2               20
    

    İkinci nesil 2 çöp toplama işlemi dördüncü aralıkta başladı ve beşinci aralıkta tamamlandı. En kötü durum varsayarsak, son çöp toplama üçüncü aralığın başında tamamlanan bir 0. nesil toplama içindi ve 2. nesil çöp toplama beşinci aralığın sonunda tamamlandı. Bu nedenle, nesil 0 çöp toplama ile 2. nesil çöp toplamanın sonu arasındaki süre 4 saniyedir. % Time in GC Sayaç 20%olduğundan, 2. nesil çöp toplama işleminin süresi üst sınırıdır (4 saniye * 20% = 800ms).

  • Alternatif olarak, atık toplama ETW olaylarını kullanarak bir çöp toplamanın uzunluğunu belirleyebilir ve atık toplama süresini belirlemek için bilgileri analiz edebilirsiniz.

    Örneğin, aşağıdaki veriler eşzamanlı olmayan çöp toplama sırasında oluşan bir olay dizisini gösterir.

    Timestamp    Event name
    513052        GCSuspendEEBegin_V1
    513078        GCSuspendEEEnd
    513090        GCStart_V1
    517890        GCEnd_V1
    517894        GCHeapStats
    517897        GCRestartEEBegin
    517918        GCRestartEEEnd
    

    Yönetilen iş parçacığının askıya alınması 26 mikrosaniye (GCSuspendEEEndGCSuspendEEBegin_V1) sürdü.

    Gerçek çöp toplama 4,8ms (GCEnd_V1GCStart_V1) sürdü.

    Yönetilen iş parçacıklarının devam ettirilmesi 21 us (GCRestartEEEndGCRestartEEBegin) sürdü.

    Aşağıdaki çıkış arka plan çöp toplama için bir örnek sağlar ve işlem, iş parçacığı ve olay alanlarını içerir. (Tüm veriler gösterilmez.)

    timestamp(us)    event name            process    thread    event field
    42504385        GCSuspendEEBegin_V1    Test.exe    4372             1
    42504648        GCSuspendEEEnd         Test.exe    4372
    42504816        GCStart_V1             Test.exe    4372        102019
    42504907        GCStart_V1             Test.exe    4372        102020
    42514170        GCEnd_V1               Test.exe    4372
    42514204        GCHeapStats            Test.exe    4372        102020
    42832052        GCRestartEEBegin       Test.exe    4372
    42832136        GCRestartEEEnd         Test.exe    4372
    63685394        GCSuspendEEBegin_V1    Test.exe    4744             6
    63686347        GCSuspendEEEnd         Test.exe    4744
    63784294        GCRestartEEBegin       Test.exe    4744
    63784407        GCRestartEEEnd         Test.exe    4744
    89931423        GCEnd_V1               Test.exe    4372        102019
    89931464        GCHeapStats            Test.exe    4372
    

    GCStart_V1 42504816'daki olay, bunun bir arka plan çöp toplaması olduğunu gösterir çünkü son alan şeklindedir1. Bu işlem, 102019 numaralı çöp toplama olur.

    Olay GCStart , arka plan çöp toplama işlemine başlamadan önce kısa süreli çöp toplamaya ihtiyaç duymanız nedeniyle oluşur. Bu, 102020 no'lu çöp toplama haline gelir.

    42514170 102020 no'lu çöp toplama işlemi tamamlanmaktadır. Yönetilen iş parçacıkları bu noktada yeniden başlatılır. Bu işlem, bu arka plan çöp toplama işlemini tetikleyen 4372 iş parçacığında tamamlandı.

    4744 düğümünde bir askıya alma gerçekleşiyor. Bu, arka plan çöp toplama işleminin yönetilen iş parçacıklarını askıya almak zorunda kaldığı tek zamandır. Bu süre yaklaşık 99ms 'dir ((63784407-63685394)/1000).

    GCEnd arka plan çöp toplama olayı 89931423'te. Bu, arka plan çöp toplama işleminin yaklaşık 47 saniye sürdüğü anlamına gelir ((89931423-42504816)/1000).

    Yönetilen iş parçacıkları çalışırken, herhangi bir sayıda geçici çöp toplama işleminin gerçekleştiğini görebilirsiniz.

Çöp toplamayı neyin tetiklediğini belirlemek için

  • SOS hata ayıklayıcısı uzantısı yüklü WinDbg veya Visual Studio hata ayıklayıcısında, çağrı yığınlarıyla tüm iş parçacıklarını göstermek için aşağıdaki komutu girin:

    ~*KB

    Bu komut çıktıyı aşağıdakine benzer şekilde görüntüler.

    0012f3b0 79ff0bf8 mscorwks!WKS::GCHeap::GarbageCollect
    0012f454 30002894 mscorwks!GCInterface::CollectGeneration+0xa4
    0012f490 79fa22bd fragment_ni!request.Main(System.String[])+0x48
    

    Atık toplama işlemi işletim sisteminden gelen düşük bellek bildiriminden kaynaklanıyorsa, iş parçacığının sonlandırıcı iş parçacığı olması dışında çağrı yığını benzerdir. Sonlandırıcı iş parçacığı zaman uyumsuz bir düşük bellek bildirimi alır ve çöp toplayıcıyı tetikler.

    Atık toplama işlemi bellek ayırmadan kaynaklanıyorsa yığın aşağıdaki gibi görünür:

    0012f230 7a07c551 mscorwks!WKS::GCHeap::GarbageCollectGeneration
    0012f2b8 7a07cba8 mscorwks!WKS::gc_heap::try_allocate_more_space+0x1a1
    0012f2d4 7a07cefb mscorwks!WKS::gc_heap::allocate_more_space+0x18
    0012f2f4 7a02a51b mscorwks!WKS::GCHeap::Alloc+0x4b
    0012f310 7a02ae4c mscorwks!Alloc+0x60
    0012f364 7a030e46 mscorwks!FastAllocatePrimitiveArray+0xbd
    0012f424 300027f4 mscorwks!JIT_NewArr1+0x148
    000af70f 3000299f fragment_ni!request..ctor(Int32, Single)+0x20c
    0000002a 79fa22bd fragment_ni!request.Main(System.String[])+0x153
    

    Tam zamanında yardımcı (JIT_New*) sonunda GCHeap::GarbageCollectGeneration'yi çağırır. 2. nesil çöp toplamaların ayırmalardan kaynaklandığını belirlerseniz, hangi nesnelerin 2. nesil çöp toplama tarafından toplandığını ve bunların nasıl önleneceğini belirlemeniz gerekir. Başka bir ifadeyle, 2. nesil çöp toplamanın başlangıcı ve sonu ile 2. nesil koleksiyonuna neden olan nesneler arasındaki farkı belirlemek istiyorsunuz.

    Örneğin, 2. nesil koleksiyonun başlangıcını göstermek için hata ayıklayıcıya aşağıdaki komutu girin:

    !dumpheap –stat

    Örnek çıkış (en çok alan kullanan nesneleri göstermek için kısaltılmış):

    79124228    31857      9862328 System.Object[]
    035f0384    25668     11601936 Toolkit.TlkPosition
    00155f80    21248     12256296      Free
    79103b6c   297003     13068132 System.Threading.ReaderWriterLock
    7a747ad4   708732     14174640 System.Collections.Specialized.HybridDictionary
    7a747c78   786498     15729960 System.Collections.Specialized.ListDictionary+DictionaryNode
    7a747bac   700298     19608344 System.Collections.Specialized.ListDictionary
    035f0ee4    89192     38887712 Toolkit.TlkOrder
    00fcae40     6193     44911636 WaveBasedStrategy.Tick_Snap[]
    7912c444    91616     71887080 System.Double[]
    791242ec    32451     82462728 System.Collections.Hashtable+bucket[]
    790fa3e0  2459154    112128436 System.String
    Total 6471774 objects
    

    2. neslin sonundaki komutu yineleyin:

    !dumpheap –stat

    Örnek çıkış (en çok alan kullanan nesneleri göstermek için kısaltılmış):

    79124228    26648      9314256 System.Object[]
    035f0384    25668     11601936 Toolkit.TlkPosition
    79103b6c   296770     13057880 System.Threading.ReaderWriterLock
    7a747ad4   708730     14174600 System.Collections.Specialized.HybridDictionary
    7a747c78   786497     15729940 System.Collections.Specialized.ListDictionary+DictionaryNode
    7a747bac   700298     19608344 System.Collections.Specialized.ListDictionary
    00155f80    13806     34007212      Free
    035f0ee4    89187     38885532 Toolkit.TlkOrder
    00fcae40     6193     44911636 WaveBasedStrategy.Tick_Snap[]
    791242ec    32370     82359768 System.Collections.Hashtable+bucket[]
    790fa3e0  2440020    111341808 System.String
    Total 6417525 objects
    

    Nesneler double[] çıktının sonundan kayboldu, yani toplandılar. Bu nesneler yaklaşık 70 MB'tır. Kalan nesneler çok fazla değişmedi. Bu nedenle, bu 2. nesil çöp toplamanın nedeni bu double[] nesnelerdi. Sonraki adımınız nesnelerin neden orada olduğunu ve neden double[] öldüklerini belirlemektir. Kod geliştiricisine bu nesnelerin nereden geldiğini sorabilir veya komutunu kullanabilirsiniz gcroot .

Yüksek CPU kullanımının çöp toplamadan kaynaklanıp kaynaklanıp kaynak edilmediğini belirlemek için

  • Bellek performansı sayacı değerini işlem süresiyle ilişkilendirin % Time in GC .

    % Time in GC Değer işlem süresiyle aynı anda ani bir artış gösterirse, atık toplama işlemi yüksek CPU kullanımına neden olur. Aksi takdirde, yüksek kullanımın nerede oluştuğunu bulmak için uygulamanın profilini oluşturun.

Ayrıca bakınız