Çöp toplama ve performans
Bu makalede çöp toplama ve bellek kullanımıyla ilgili sorunlar açıklanmaktadır. Yönetilen yığınla ilgili sorunları ele alır ve çöp toplamanın uygulamalarınız üzerindeki etkisinin nasıl en aza indirgenebileceğini açıklar. Her başlıkta, problemleri araştırmak için kullanabileceğiniz prosedürlerin bağlantıları yer alı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ılabilen araçlar açıklanmaktadır. Bu makalenin devamında sağlanan yordamlar bu araçlara başvurur.
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.
Çöp 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, çöp toplama olayı gerçekleşmek üzereyken oluşturulan GCStart_V1
olayı, aşağıdaki bilgileri sağlar:
- Hangi nesne neslinin toplandığı.
- Çöp toplama işlemini neyin tetiklediği.
- Çöp toplama işleminin türü (eşzamanlı veya eşzamansız).
ETW olay günlüğü verimlidir ve çöp toplamayla ilgili hiçbir performans sorununu gizlemez. Bir işlem, ETW olaylarıyla birlikte kendi olaylarını sağlayabilir. Günlüğe kaydedildiğinde, yığın problemlerinin nasıl ve ne zaman oluştuğunu belirlemek için hem uygulamanın olayları hem de çöp toplama olayları eşleştirilebilir. Örneğin bir sunucu uygulaması, olayları bir istemci isteğinin başında ve sonunda sağlayabilir.
Profil Oluşturma API'si
Ortak dil çalışma zamanı (CLR) profil oluşturma arabirimleri, çöp toplama işlemi sırasında etkilenen nesneler hakkında detaylı bilgi sağlar. Bir çöp toplama işlemi başladığında ve bittiğinde bir profil oluşturucu bildirim alabilir. Her nesildeki nesnelerin bir tanımlaması dahil olmak üzere yönetilen yığındaki nesneler hakkında raporlar sağlayabilir. Daha fazla bilgi için bkz . Profil Oluşturma'ya Genel Bakış.
Profil oluşturucular kapsamlı bilgi 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. Eğer sorunun bu olduğunu belirlerseniz, aşağıdaki listeden sorunu gidermeyi seçin.
- Bellek yetersiz özel durumu oluştu
- İşlem çok fazla bellek kullanıyor
- Çöp toplayıcı nesneleri yeterince hızlı geri kazanmıyor
- Yönetilen yığın çok parçalanmış
- Çöp toplama durakları çok uzun
- 0. nesil çok büyük
- Çöp toplama sırasında CPU kullanımı çok yüksek
Sorun: Bir Yetersiz Bellek Özel Durumu Oluşturuldu
Yönetilen bir OutOfMemoryException oluşturulması için iki meşru durum vardır:
Sanal bellek tükeniyor.
Çöp toplayıcısı önceden belirlenmiş bir boyutun segmentlerindeki sistemden bellek ayırır. Eğer bir ayırma işlemi için ek bir segment gerekirse, ancak işlemin sanal bellek alanının bitişiğinde boş bir blok kalmamışsa, yönetilen yığın için ayırma başarısız olur.
Ayrılacak yeterli fiziksel belleğe sahip olmama.
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 meşru olmadığını belirlerseniz, aşağıdaki bilgilerle Microsoft Müşteri Hizmetleri ve Destek birimiyle iletişime geçin:
- Yönetilen yetersiz bellek özel durumu olan yığın.
- Tam bellek dökümü.
- Sanal veya fiziksel belleğin bir sorun olmadığını gösteren veriler dahil olmak üzere, meşru bir yetersiz bellek özel durumu 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 ekran çalışan kümeyle ilgilidir; sanal bellek kullanımı hakkında bilgi sağlamaz.
Eğer sorunun yönetilen yığından kaynaklı olduğunu belirlerseniz, herhangi bir düzen olup olmadığını belirlemek için yönetilen yığını zamanla ölçmeniz gerekir.
Eğer problemin yönetilen yığından kaynaklanmadığını belirlerseniz, yerel hata ayıklama kullanmanız gerekir.
Sorun: Atık Toplayıcısı Nesneleri Yeterince Hızlı Geri Kazanmıyor
Çöp toplama işlemi için nesnelerin beklendiği kadar hızlı geri kazanılmadığı anlaşıldığında, bu nesnelere yapılan güçlü atıflar olup olmadığını belirlemeniz gerekir.
Etkin olmayan nesneye ait sonlandırıcının çalıştırılmadığını gösteren etkin olmayan bir nesne içeren nesilde hiç çöp toplama olmaması durumunda da bu sorunla karşılaşabilirsiniz. Örneğin, bir tek iş parçacıklı bölme (STA) uygulamasını çalıştırdığınızda ve sonlandırıcı sıraya hizmet veren iş parçacığı bu uygulamaya çağrılamadığında mümkün olur.
Performans denetimleri |
---|
Nesnelere başvuruları 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 Yığın Çok Parçalanmış
Parçalanma düzeyi, boş alanın nesil için ayrılan toplam belleğe oranı olarak hesaplanır. Nesil 2 için, kabul edilebilir parçalanma düzeyi %20'den fazla değildir. Nesil 2 çok fazla büyüyebildiğinden, parçalanma oranı mutlak değerden daha önemlidir.
Nesil 0, yeni nesnelerin ayrıldığı nesil olduğundan, içerisinde fazla boş alan olması problem değildir.
Parçalanma, sıkıştırılmış olmadığından her zaman büyük nesne yığınında oluşur. Bitişik olan boş nesneler, büyük nesne ayırma isteklerini karşılamak için doğal olarak tek bir boşluk içine daraltılır.
Nesil 1 ve nesil 2'de parçalanma bir sorun olabilir. Eğer bu nesiller çöp toplama sonrasında büyük bir boş alana sahipse, uygulamanın nesne kullanımının değiştirilmesi gerekebilir ve uzun zamanlı nesnelerin kullanım sürelerini yeniden değerlendirmeyi göz önünde bulundurmanız gerekir.
Aşırı nesne sabitlenmesi parçalanmayı arttırabilir. Parçalanma yüksekse, çok fazla nesne sabitlenmiş olabilir.
Sanal belleğin parçalanması toplamanın segment eklemesini engelliyorsa, bunun sebebi aşağıdakilerden biri olabilir:
Birçok küçük derlemenin sık sık yüklenmesi ve kaldırılması.
Yönetilemeyen kodla karşılıklı çalışılırken COM nesnelerinde çok fazla atıf tutulması.
Büyük nesne yığınının sık sık yığın segmentlerinin ayrılmasına ve boşaltılmasına neden olan büyük geçici nesnelerin oluşturulması.
Bir uygulama CLR'yi barındırdığı sırada çöp toplayıcıdan segmentlerini 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ş nesne sayısını belirleyin. |
Eğer parçalanma için meşru bir neden olmadığını düşünüyorsanız, Microsoft Müşteri Hizmetleri ve Destek'le iletişime geçin.
Sorun: Atık Toplama Duraksamaları Çok Uzun
Çöp toplama gerçek zamanlı olarak çalıştığından, bir uygulamanın bazı duraklamalara izin vermesi gerekir. Yazılımsal olarak gerçek zamanlı çalışmanın bir kriteri, işlemlerin %95'inin zamanında bitmesi gerektiğidir.
Eşzamanlı çöp toplamada, bir toplama işlemi sırasında yönetilen iş parçacıklarının çalışmasına izin verilir, bu ise çok az duraklama olacağı anlamına gelir.
Kısa ömürlü çöp toplama işlemleri (nesil 0 ve 1) yalnızca birkaç milisaniye sürdüğünden, duraksamaların azaltılması genellikle mantıklı değildir. Ancak, bir uygulama tarafından yapılan ayırma isteklerinin düzenini değiştirerek nesil 2 koleksiyonlarındaki duraksamaları azaltabilirsiniz.
Daha doğru bir diğer yöntem de atık toplama ETW olaylarını kullanmaktır. Bir olay dizisine ait zaman damgalarının farklarını ekleyerek koleksiyonlar için zamanlamaları 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 sürdürülmesini 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: Nesil 0 Çok Büyük
Özellikle iş istasyonu çöp toplama yerine sunucu çöp toplamayı kullandığınızda, nesil 0, 64 bit bir sistem üzerinde genellikle çok sayıda nesneye sahip olur. Bunun sebebi, bir nesil 0 atık temizleme işlemini tetikleme eşiğinin bu ortamlarda daha yüksek olması ve nesil 0 toplama işlemlerinin çok daha fazla büyüyebilecek olmasıdır. Bir çöp toplama tetiklenmeden önce bir uygulama daha fazla bellek ayırırsa performans artar.
Sorun: Bir Atık Toplama İşlemi Sırasında CPU Kullanımı Çok Yüksek
Çöp toplama sırasında CPU kullanımı yüksek olacaktır. Eğer bir çöp toplama işlemi sırasında önemli miktarda işlem süresi harcanırsa, toplama işlemi çok sık gerçekleşiyordur veya çok uzun sürüyordur. Yönetilen yığındaki nesnelerin arttırılmış ayırma oranı, çöp toplamanın daha sık gerçekleşmesine neden olur. Ayırma oranının azaltılması çöp toplamaların sıklığını azaltır.
Allocated Bytes/second
performans sayacını kullanarak ayırma oranlarını izleyebilirsiniz. Daha fazla bilgi için bkz . .NET'te Performans Sayaçları.
Bir koleksiyonun süresi, öncelikle ayırma sonrası varlığını sürdüren nesnelerin sayısında bir etmendir. Toplanacak çok nesne kaldıysa çöp toplayıcının büyük miktarda belleği gözden geçirmesi gerekir. Dışarıda kalanların sıkıştırılması, zaman alan bir işlemdir. Bir toplama sırasında kaç nesnenin işlendiğini belirlemek için belirli bir nesle yönelik bir çöp toplamanın sonundaki 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şlamadan önce göz önünde bulundurmanız gereken yönergeler açıklanmaktadır.
İş İstasyonu veya Sunucu Atık Toplama
Doğru çöp toplama türünü kullanıp kullanmadığınızı belirleyin. Uygulamanız birden çok iş parçacığı ve nesne örneği kullanıyorsa, iş istasyonu çöp toplama yerine sunucu çöp toplama kullanın. İş istasyonu çöp toplama, 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 yarışmasını gerektirirken sunucu çöp toplama, birden çok iş parçacığında çalışır.
Bir hizmet gibi düşük yüke sahip ve arka planda seyrek olarak çalışan bir uygulama, eşzamanlı çöp toplama özelliği devre dışı bırakılmış iş istasyonu çöp toplamayı kullanabilir.
Yönetilen Yığın Boyutu Ne Zaman Ölçülmeli
Bir profil oluşturucu kullanmıyorsanız, performans sorunlarını etkili bir biçimde tanılamak için tutarlı bir ölçüm düzeni oluşturmanız gerekecektir. Bir zamanlama oluşturmak için aşağıdaki noktaları göz önünde bulundurun:
- Bir nesil 2 çöp toplamanın ardından ölçerseniz, yönetilen bütün yığın atıktan arınmış olacaktır (etkin olmayan nesneler).
- Bir nesil 0 çöp toplamanın hemen ardından ölçerseniz nesil 1 ve 2'deki nesneler henüz toplanmamış olacaktır.
- Bir çöp toplamadan hemen önce ölçerseniz, çöp toplama başlamadan önce mümkün olduğunca fazla ayırmayı ölçersiniz.
- Çöp toplama veri yapıları gezinme için geçerli bir durumda olmadığından ve size tam sonuçlar vermeyebileceğinden çöp toplama sırasında ölçüm yapmak çeşitli sorunlara yol açar. Bu tasarım gereğidir.
- Eşzamanlı çöp toplama özellikli iş istasyonu çöp toplama kullandığınızda, geri kazanılan nesneler sıkıştırılmayacağından, yığın boyutu aynı veya daha büyük olabilir (parçalanma boyutu daha büyük gösterebilir).
- Nesil 2'deki eşzamanlı çöp toplama, fiziksel bellek yükü çok fazla olduğunda geciktirilir.
Aşağıdaki yordam, yönetilen yığını ölçmek için nasıl bir kesme noktası ayarlayacağınızı açıklar.
Çö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 nesle 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 toplamada, yalnızca bir iş parçacığı çağırır
RestartEE
, bu nedenle kesme noktası 2. nesil çöp toplama sırasında yalnızca bir kez gerçekleşir.
Performans denetimi yordamları
Bu bölümde, performans sorunlarınızın sebeplerini ortadan kaldırmak için aşağıdaki yordamlar açıklanmaktadır:
- Sorunun çöp toplamadan kaynaklanıp kaynak olmadığını belirleyin.
- 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.
- 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.
- Nesnelere başvuruları belirleme.
- 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.
- Yönetilen yığındaki boş alan miktarını belirleyin.
- Sabitlenmiş nesne sayısını belirleyin.
- Bir çöp toplamadaki sürenin uzunluğunu belirleyin.
- Çöp toplamayı neyin tetiklediğini belirleyin.
- Atık toplamadan kaynaklanan yüksek CPU kullanımı olup olmadığını belirleyin.
Sorunun çöp toplamadan kaynaklanıp kaynaklanmadığını belirlemek için
Şu iki bellek performans sayacını inceleyin:
GC'de Süre % . Son çöp toplama döngüsünden sonra gerçekleşen bir çöp toplamaya harcanan süresinin yüzdesini gösterir. Bu sayacı kullanarak çöp toplayıcısının yönetilen yığın alanı açmak için ne kadar süre harcadığını belirleyebilirsiniz. Eğer çöp toplamaya harcanan süre göreceli olarak düşükse, bu, yönetilen yığın dışında bir kaynak problemi olduğunu gösteriyor olabilir. Bu sayaç, süreçte eş zamanlı veya arka plan çöp toplama işlemleri varsa düzgün olmayabilir.
# Toplam işlenen Bayt sayısı. Çöp toplayıcısı tarafından o an yürütülen sanal bellek miktarını gösterir. Bu sayacı kullanarak çöp toplayıcı tarafından uygulamanızın kullandığı belleğin aşırı bir kısmının kullanılıp kullanılmadığını belirleyebilirsiniz.
Bellek performans sayaçlarının çoğu her çöp toplama işleminin sonunda güncelleştirilir. Bu nedenle, hakkında bilgi almak istediğiniz geçerli koşulları yansıtmayabilir.
Yetersiz bellek özel durumunun yönetilip yönetilmediğini 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 yazdırma özel durumu (
pe
) komutunu girin:!pe
Eğer özel durum yönetiliyorsa, aşağıdaki örnekte gösterildiği gibi, istisna türü OutOfMemoryException olarak gösterilir.
Exception object: 39594518 Exception type: System.OutOfMemoryException Message: <none> InnerException: <none> StackTrace (generated):
Eğer çıktıda bir özel durum belirtilmezse, bellek yetmezliği özel durumunun hangi iş parçacığından kaynaklandığını 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
Özel durum çağrısı yapan yığınlı iş parçacığı,
RaiseTheException
bağımsız değişkeni tarafından belirtilir. Bu yönetilen özel durum nesnesidir.28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0
İç içe özel durumların dökümünü almak için aşağıdaki komutu kullanabilirsiniz.
!pe -nested
Eğer herhangi bir özel durum bulamazsanız, bellek yetmezliği özel durumu, yönetilmeyen koddan kaynaklanmıştı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 boş bölge aşağıdaki çıktıda gösterildiği gibi görüntülenir.
Largest free region: Base 54000000 - Size 0003A980
Bu örnekte, en büyük boş bölge yaklaşık olarak 24000 KB büyüklüğündedir (onaltılık sistemde 3A980). Bu bölgenin boyutu, çöp toplayıcının bir segment için ihtiyaç duyduğu boyuttan daha küçüktür.
-Veya-
vmstat
Komutunu kullanın:!vmstat
En büyük boş bölge, aşağıdaki çıktıda görüldüğü üzere, 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
Windows Görev Yöneticisi'ni başlatın.
Performance
Sekmesinde, işlenen değere bakın. (Windows 7'deSystem group
,Commit (KB)
.)Total
değerine yakınsaLimit
, fiziksel belleğiniz azalıyordur.
Yönetilen yığının ne kadar bellek kullandığını belirlemek için
Yönetilen yığının kullandığı bayt sayısını elde etmek için
# Total committed bytes
bellek performans sayacını kullanın. Çöp toplayıcı yığınların hepsini aynı zamanda değil, ihtiyaç duyulan bir segmentte yürütür.Not
# Bytes in all Heaps
performans sayacı yönetilen yığın tarafından kullanılan gerçek bellek kullanımını göstermediğinden, bu sayacı kullanmayın. Bu değere bir neslin boyutu dahildir ve aslında onun eşik sınırı, yani, eğer nesil nesnelerle doluysa bir çöp toplama işlemini başlatan boyutu gösterir. Bu nedenle, bu değer genellikle sıfırdır.
Yönetilen yığının ne kadar bellek ayırdığını belirlemek için
# Total reserved bytes
bellek performans sayacını kullanın.Çöp toplayıcı, segmentlerdeki belleği ayırır ve komutunu kullanarak bir kesimin nereden başlayacağını
eeheap
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" ifadesiyle gösterilen adresler, segmentlerin başlangıç adresleridir.
Nesil 2'deki 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 tamamlanması
dumpheap
biraz zaman alabilir.Analize çıktının son satırlarından başlayabilirsiniz çünkü en çok alan kullanan nesneler burada listelenmektedir. Ö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
En son listelenen nesne bir dizedir ve en çok yeri o kaplar. Dize nesnelerinin nasıl optimize edilebileceğ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ğıdaki gibidir.
Address MT Size Gen 1875d2c0 790fa3e0 152 2 System.String HighlightNullStyle_Blotter_PendingOrder-11_Blotter_PendingOrder-11 …
ID için dize yerine tamsayı kullanmak daha verimli olabilir. Aynı dize binlerce kez yineleniyorsa, dize kopyasını kullanmayı düşünün. Dize kopyası kullanımı hakkında daha fazla bilgi edinmek için, String.Intern yöntemine yönelik referans konusuna bakın.
Nesnelere olan 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 yapılan atıfları belirlemek için, şu adresleri ekleyin:
!gcroot 1c37b2ac
Yığınlar üzerinde bulunan kökler yanlış pozitif 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 iade alınmayan her nesne yaşayan bir nesnedir. Başka bir deyişle, bir kök doğrudan veya dolaylı olarak nesne üzerinde tutun, bu nedenlegcroot
nesneye yol bilgileri döndürmelidir. Döndürülen grafikleri ve bu nesnelere neden hala atıf yapıldığını incelemeniz gerekir.
Bir 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 işleminin sorunu çözmesi, sorunun, o nesnelere yönelik sonlandırıcılar askıya alındığı için çöp toplayıcının nesneleri iade almamasından kaynaklandığı anlamına gelir. GC.WaitForPendingFinalizers yöntemi, işlemlerini tamamlaması ve problemi gidermesi için sonlandırıcıları etkinleştirir.
Sonlandırılmayı bekleyen nesneler olup olmadığı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:
!finalizequeue
Sonlandırılmaya hazır olan nesnelerinin sayısına bakın Eğer sayı yüksekse, o sonlandırıcıların niye ilerlemediğini veya yeterince hızlı olmadığını incelemeniz gerekir.
İş parçacıklarının çıkışını almak için aşağıdaki komutu girin:
!threads -special
Bu komut aşağıdaki gibi bir çıktı sağlar.
OSID Special thread type 2 cd0 DbgHelper 3 c18 Finalizer 4 df0 GC SuspendEE
Sonlandırıcı iş parçacığı, varsa, o an çalışmakta olan sonlandırıcıyı gösterir. Bir sonlandırıcı iş parçacığı herhangi bir sonlandırıcı çalıştırmıyorsa, ona işini söyleyecek bir olay bekliyordur. Çoğu zaman sonlandırıcı iş parçacığını bu durumda görürsünüz çünkü THREAD_HIGHEST_PRIORITY'de çalışır ve varsa çalışan sonlandırıcıları çok hızlı sonlandırması gerekir.
Yönetilen yığında ne kadar boş alan olduğunu 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 de 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, aşağıdakine benzer bir çıktı gösterir. Son satır kısa ömürlü 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)
Nesil 0 tarafından kullanılan alanı hesaplayın:
? 49e05d04-0x49521f8c
Sonuç aşağıdaki gibidir. Nesil 0 yaklaşık olarak 9 MB.
Evaluate expression: 9321848 = 008e3d78
Aşağıdaki komut, nesil 0 aralığındaki boş alanların dökümünü verir:
!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 çıktı, yığının nesil 0 bölümünün nesneler için 9 MB alan kullandığını 7 MB boş alana sahip olduğunu göstermektedir. Bu çözümleme nesil 0'ın parçalanmaya ne kadar katkıda bulunduğunu gösterir. Bu yığın kullanımının miktarı, uzun zamanlı nesnelerden kaynaklanan parçalanma nedenlerinin toplam miktarından çıkarılmalıdır.
Sabitlenen nesne 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, aşağıdaki örnekte gösterildiği gibi, sabitlenen işleyicilerin sayısını içerir.
GC Handle Statistics: Strong Handles: 29 Pinned Handles: 10
Bir çöp toplama işleminde sürenin uzunluğunu belirlemek için
% Time in GC
bellek performans sayacını inceleyin.Değer, örnek bir zaman aralığı kullanılarak hesaplanır. Her çöp toplama işlemi sonrası sayaçlar güncellendiğinden, ikisi arasında bir toplama işlemi gerçekleşmediyse geçerli örnek öncekiyle aynı değere sahip olacaktır.
Toplama süresi, örnek zaman aralığının yüzde değeri ile çarpılarak elde edilir.
Aşağıdaki veriler, 8 saniyelik bir çalışma için ikişer saniyelik dört örnek aralığını göstermektedir.
Gen0
,Gen1
veGen2
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
Çöp toplama işleminin ne zaman gerçekleştiği bu bilgilerde yer almaz, ancak belirli bir zaman aralığında gerçekleşen çöp toplama işlemi 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 çöp toplama işleminin sonuyla on birinci işlemin sonu arasında geçen süre, yaklaşık 2 saniyedir ve performans sayacı %3'ü gösterdiğinden, on birinci nesil 0 çöp toplamanın süresi (2 saniye * 3% = 60 ms)'dir.
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 toplamanın sonu ile nesil 2 çöp toplamanın sonu arasında geçen süre 4 saniyedir.
% Time in GC
sayacı %20 olduğundan, nesil 2 çöp toplama en fazla (4 saniye * 20% = 800 ms) sürmüş olabilir.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 bir çöp toplama işlemi sırasında meydana gelen 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ı askıya almak 26 us sürüyor (
GCSuspendEEEnd
–GCSuspendEEBegin_V1
).Çöp toplama işleminin kendisi 4,8 ms sürmüş (
GCEnd_V1
–GCStart_V1
).Yönetilen parçacığını devam ettirmek 21 us sürüyor (
GCRestartEEEnd
–GCRestartEEBegin
).Aşağıdaki çıktıda bir arkaplan çöp toplama örneği verilmiştir ve işlem, iş parçacığı ve olay alanlarını içerir. (Tüm veriler gösterilmemektedir.)
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
Son alan
GCStart_V1
olduğundan, 42504816'daki1
olayı, bunun bir arkaplan çöp toplama olduğunu gösterir. Bu, çöp toplama no. 102019 olur.GCStart
olayı, bir arkaplan çöp toplama işlemi başlamadan önce geçici bir çöp toplama işlemine ihtiyaç duyulduğu için gerçekleşir. Bu, 102020 no'lu çöp toplamaya dönüşür.42514170 102020 no'lu çöp toplama işlemi tamamlanmaktadır. Yönetilen iş parçacıkları bu noktada yeniden başlatılır. Bu, arkaplan çöp toplama işlemini tetikleyen 4372 numaralı iş parçacığı üzerinde tamamlanır.
4744 numaralı iş parçacığında bir askıya alma meydana gelir. Bu, arkaplan çöp toplamanın yönetilen iş parçacıklarını askıya almasının gerektiği tek zamandır. Bu süre yaklaşık olarak 99 ms'dir ((63784407-63685394)/1000).
Arkaplan çöp toplama için
GCEnd
olayı 89931423'tedir. Bu, arkaplan çöp toplamanın yaklaşık 47 saniye sürdüğü anlamına gelir ((89931423-42504816)/1000).Yönetilen iş parçacıkları çalışırken, belirli bir sayıda geçici çöp toplama işleminin gerçekleştiğini görebilirsiniz.
Bir çöp toplama işlemini 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, aşağıdakine benzer bir çıktı gösterir.
0012f3b0 79ff0bf8 mscorwks!WKS::GCHeap::GarbageCollect 0012f454 30002894 mscorwks!GCInterface::CollectGeneration+0xa4 0012f490 79fa22bd fragment_ni!request.Main(System.String[])+0x48
Çöp toplama işlemine işletim sisteminden kaynaklanan bir düşük bellek bildirimi yol açmışsa, çağrı yığını benzerdir ama iş parçacığı sonlandırıcı iş parçacığıdır. Sonlandırıcı iş parçacığı zaman uyumsuz bir düşük bellek bildirimi alır ve çöp toplama işlemini başlatır.
Çöp toplama işlemine bellek ayırma yol açtıysa, 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
Bir tam zamanında yardımcı olan (
JIT_New*
), sonundaGCHeap::GarbageCollectGeneration
komutuna çağrı yapar. Eğer nesil 2 çöp toplamaya ayırmaların neden olduğunu belirlerseniz, nesil 2 bir çöp toplama işlemi tarafından hangi nesnelerin toplandığını ve bunlardan nasıl kaçınabileceğinizi belirlemeniz gerekir. Yani, nesil 2 bir çöp toplama işleminin başıyla ve sonu arasındaki farkı ve nesil 2'ye ait bir toplama işlemine neden olan nesneleri belirlemeniz faydalı olur.Ö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 çıktı (en çok alan kullanan nesneleri göstermek için kısaltılmıştır):
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
Nesil 2 sonunda komutu yineleyin:
!dumpheap –stat
Örnek çıktı (en çok alan kullanan nesneleri göstermek için kısaltılmıştır):
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
Çıktının sonunda
double[]
nesneleri kaybolduğundan, bunların toplandığını anlayabiliriz. Bu nesneler yaklaşık olarak 70 MB. Geri kalan nesneler pek değişmemiş. Bu nedenle, bu nesil 2 çöp toplama işleminin meydana gelmesinin nedeni, budouble[]
nesneleridir. Bir sonraki adımınız,double[]
nesnelerinin neden orada olduğu ve neden öldüğünü belirlemek olacaktır. Kod geliştiricisine bu nesnelerin nereden geldiğini sorabilir veya komutunu kullanabilirsinizgcroot
.
Yüksek CPU kullanımına çöp toplamanın sebep olup olmadığını belirlemek için
% Time in GC
bellek performans sayaç değeriyle işlem süresini karşılaştırın.% Time in GC
değeri işlem süresiyle aynı anda artıyorsa, yüksek CPU kullanımına çöp toplama işlemi neden oluyor demektir. Böyle olmuyorsa, yüksek kullanımın nerede meydana geldiğini bulmak için uygulamayı profilleyin.