Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale şunlar için geçerlidir: ✔️ .NET Core 3.1 SDK ve sonraki sürümler
Uygulamanız artık istenen görevi gerçekleştirmek için gerekmeyen nesnelere başvurduğunda bellek sızıntıya neden olabilir. Bu nesnelere başvurmak, çöp toplayıcının kullanılan belleği geri kazanmasını engeller. Bu, performans düşüşüne ve bir OutOfMemoryException istisnanın atılmasına yol açabilir.
Bu öğretici, .NET tanılama CLI araçlarını kullanarak bir .NET uygulamasındaki bellek sızıntısını analiz etme araçlarını gösterir. Windows kullanıyorsanız, bellek sızıntısında hata ayıklamak için Visual Studio'nun Bellek Tanılama araçlarını kullanabilirsiniz .
Bu öğreticide, alıştırma amacıyla bilinçli olarak bellek sızdıran bir örnek uygulama kullanılmaktadır. İstenmeyen bellek sızıntısı olan uygulamaları da analiz edebilirsiniz.
Bu kılavuzda aşağıdakileri yapacaksınız:
- dotnet-counters ile yönetilen bellek kullanımını inceleyin.
- Döküm dosyası oluşturun.
- Döküm dosyasını kullanarak bellek kullanımını analiz edin.
Önkoşullar
Eğiticide şunlar kullanılıyor:
- .NET Core 3.1 SDK veya sonraki bir sürüm.
- yönetilen bellek kullanımını denetlemek için dotnet-counters.
- döküm dosyasını toplamak ve analiz etmek için dotnet-dump (SOS hata ayıklama uzantısını içerir).
- Tanılamak için örnek bir hata ayıklama hedefi uygulaması.
Kılavuzda, örnek uygulamaların ve araçların yüklendiği ve kullanıma hazır olduğu varsayılır.
Uygulamanız .NET 9'dan daha eski bir .NET sürümü çalıştırıyorsa dotnet-counters çıkış kullanıcı arabirimi biraz farklı görünür; Ayrıntılar için dotnet-counters bölümüne bakın.
Yönetilen bellek kullanımını inceleme
Bu senaryonun kök nedenini belirlemeye yardımcı olacak tanılama verilerini toplamaya başlamadan önce, gerçekten bir bellek sızıntısı (bellek kullanımında artış) gördüğünüzden emin olun. Bunu onaylamak için dotnet-counters aracını kullanabilirsiniz.
Bir konsol penceresi açın ve örnek hata ayıklama hedefini indirip sıkıştırmasını açtığınız dizine gidin. Hedefi çalıştırın:
dotnet run
Ayrı bir konsoldan işlem kimliğini bulun:
dotnet-counters ps
Çıkış şuna benzer olmalıdır:
4807 DiagnosticScena /home/user/git/samples/core/diagnostics/DiagnosticScenarios/bin/Debug/netcoreapp3.0/DiagnosticScenarios
Uyarı
Önceki komut çalışmazsa veya bulunamazsa, büyük olasılıkla önce aracı yüklemeniz dotnet-counters gerekir. Aşağıdaki komutu kullanın:
dotnet tool install --global dotnet-counters
Şimdi dotnet-counters aracıyla yönetilen bellek kullanımını denetleyin.
--refresh-interval yenilemeler arasındaki saniye sayısını belirtir.
dotnet-counters monitor --refresh-interval 1 -p 4807
Canlı çıkış şuna benzer olmalıdır:
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[System.Runtime]
dotnet.assembly.count ({assembly}) 111
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 1
gen1 0
gen2 0
dotnet.gc.heap.total_allocated (By) 4,431,712
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 803,576
gen1 15,456
gen2 0
loh 0
poh 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,960
gen1 1,214,720
gen2 0
loh 0
poh 24,528
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
dotnet.gc.pause.time (s) 0.003
dotnet.jit.compilation.time (s) 0.329
dotnet.jit.compiled_il.size (By) 120,212
dotnet.jit.compiled_methods ({method}) 1,202
dotnet.monitor.lock_contentions ({contention}) 2
dotnet.process.cpu.count ({cpu}) 22
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.344
user 0.344
dotnet.process.memory.working_set (By) 64,331,776
dotnet.thread_pool.queue.length ({work_item}) 0
dotnet.thread_pool.thread.count ({thread}) 0
dotnet.thread_pool.work_item.count ({work_item}) 7
dotnet.timer.count ({timer}) 0
Şu satıra odaklanın:
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
Yönetilen yığın belleğinin başlangıçtan hemen sonra 4 MB olduğunu görebilirsiniz.
Şimdi URL'ye https://localhost:5001/api/diagscenario/memleak/20000gidin.
Bellek kullanımının 20 MB'ın üzerine geldiğini gözlemleyin.
dotnet.gc.last_collection.memory.committed_size (By) 21,020,672
Bellek kullanımını izleyerek, belleğin arttığını veya sızdırıldığını güvenle söyleyebilirsiniz. Sonraki adım, bellek analizi için doğru verileri toplamaktır.
Bellek dökümü oluşturma
Olası bellek sızıntılarını analiz ederken, bellek içeriğini analiz etmek için uygulamanın bellek yığınına erişmeniz gerekir. Nesneler arasındaki ilişkilere baktığınızda, belleğin neden serbest kalmadığının teorilerini oluşturursunuz. Yaygın bir tanılama veri kaynağı, Windows'da bellek dökümü veya Linux'ta eşdeğer çekirdek dökümüdür. Bir .NET uygulamasının dökümünü oluşturmak için dotnet-dump aracını kullanabilirsiniz.
Daha önce başlatılan örnek hata ayıklama hedefini kullanarak bir Linux çekirdek dökümü oluşturmak için aşağıdaki komutu çalıştırın:
dotnet-dump collect -p 4807
Sonuç, aynı klasörde bulunan bir core dump'tır.
Writing minidump with heap to ./core_20190430_185145
Complete
Uyarı
Zaman içinde bir karşılaştırma için, ilk dökümü topladıktan sonra özgün işlemin çalışmaya devam etmesine ve ikinci bir dökümü aynı şekilde toplamasına izin verin. Daha sonra, belli bir süre boyunca karşılaştırabileceğiniz iki bellek dökümüne sahip olursunuz, bu da bellek kullanımının hangi alanlarda arttığını görmenizi sağlar.
Başarısız işlemi yeniden başlatma
Bellek dökümü toplandıktan sonra başarısız işlemi tanılamak için yeterli bilgiye sahip olmuş olacaksınız. Başarısız işlem bir üretim sunucusunda çalışıyorsa, işlemi yeniden başlatarak kısa vadeli düzeltme için ideal zamandır.
Bu öğreticide artık Örnek hata ayıklama hedefiyle işinizi bitirdiniz ve onu kapatabilirsiniz. Sunucuyu başlatan terminale gidin ve Ctrl+C tuşlarına basın.
Çekirdek dökümünü analiz et
Çekirdek dökümü oluşturduğunuza göre, dökümü analiz etmek için dotnet-dump aracını kullanın:
dotnet-dump analyze core_20190430_185145
Burada core_20190430_185145 , analiz etmek istediğiniz çekirdek dökümünün adıdır.
Uyarı
libdl.so bulunamadığını belirten bir hata görürseniz libc6-dev paketini yüklemeniz gerekebilir. Daha fazla bilgi için bkz. Linux üzerinde .NET önkoşulları.
SOS komutlarını girebileceğiniz bir istem gösterilir. Genellikle, bakmak istediğiniz ilk şey yönetilen yığının genel durumudur:
> dumpheap -stat
Statistics:
MT Count TotalSize Class Name
...
00007f6c1eeefba8 576 59904 System.Reflection.RuntimeMethodInfo
00007f6c1dc021c8 1749 95696 System.SByte[]
00000000008c9db0 3847 116080 Free
00007f6c1e784a18 175 128640 System.Char[]
00007f6c1dbf5510 217 133504 System.Object[]
00007f6c1dc014c0 467 416464 System.Byte[]
00007f6c21625038 6 4063376 testwebapi.Controllers.Customer[]
00007f6c20a67498 200000 4800000 testwebapi.Controllers.Customer
00007f6c1dc00f90 206770 19494060 System.String
Total 428516 objects
Burada çoğu nesnenin String veya Customer nesne olduğunu görebilirsiniz.
Tüm dumpheap örneklerin String listesini almak için komutunu yöntem tablosuyla (MT) yeniden kullanabilirsiniz:
> dumpheap -mt 00007f6c1dc00f90
Address MT Size
...
00007f6ad09421f8 00007faddaa50f90 94
...
00007f6ad0965b20 00007f6c1dc00f90 80
00007f6ad0965c10 00007f6c1dc00f90 80
00007f6ad0965d00 00007f6c1dc00f90 80
00007f6ad0965df0 00007f6c1dc00f90 80
00007f6ad0965ee0 00007f6c1dc00f90 80
Statistics:
MT Count TotalSize Class Name
00007f6c1dc00f90 206770 19494060 System.String
Total 206770 objects
gcroot komutunu bir System.String örneğinde kullanarak nesnenin nasıl ve neden kök saldığını görebilirsiniz.
> gcroot 00007f6ad09421f8
Thread 3f68:
00007F6795BB58A0 00007F6C1D7D0745 System.Diagnostics.Tracing.CounterGroup.PollForValues() [/_/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs @ 260]
rbx: (interior)
-> 00007F6BDFFFF038 System.Object[]
-> 00007F69D0033570 testwebapi.Controllers.Processor
-> 00007F69D0033588 testwebapi.Controllers.CustomerCache
-> 00007F69D00335A0 System.Collections.Generic.List`1[[testwebapi.Controllers.Customer, DiagnosticScenarios]]
-> 00007F6C000148A0 testwebapi.Controllers.Customer[]
-> 00007F6AD0942258 testwebapi.Controllers.Customer
-> 00007F6AD09421F8 System.String
HandleTable:
00007F6C98BB15F8 (pinned handle)
-> 00007F6BDFFFF038 System.Object[]
-> 00007F69D0033570 testwebapi.Controllers.Processor
-> 00007F69D0033588 testwebapi.Controllers.CustomerCache
-> 00007F69D00335A0 System.Collections.Generic.List`1[[testwebapi.Controllers.Customer, DiagnosticScenarios]]
-> 00007F6C000148A0 testwebapi.Controllers.Customer[]
-> 00007F6AD0942258 testwebapi.Controllers.Customer
-> 00007F6AD09421F8 System.String
Found 2 roots.
String nesnesinin Customer nesnesi tarafından doğrudan, CustomerCache nesnesi tarafından dolaylı olarak tutulduğunu görebilirsiniz.
Çoğu nesnenin benzer bir desen izlediğini görmek için nesneleri dökmeye devam edebilirsiniz. Bu noktada araştırma, kodunuzdaki kök nedeni tanımlamak için yeterli bilgi sağladı.
Bu genel yordam, ana bellek sızıntılarının kaynağını belirlemenize olanak tanır.
Kaynakları temizle
Bu öğreticide örnek bir web sunucusu başlattınız. Bu sunucu , Başarısız işlemi yeniden başlatma bölümünde açıklandığı gibi kapatılmış olmalıdır.
Ayrıca, oluşturulan döküm dosyasını silebilirsiniz.
Ayrıca bakınız
- dotnet-trace ile işlemleri listele
- yönetilen bellek kullanımını denetlemek için dotnet-counters
- döküm dosyasını toplamak ve analiz etmek için dotnet-dump
- dotnet/diagnostics
- Bellek sızıntılarında hata ayıklamak için Visual Studio kullanma