.NET'te bellek sızıntılarını bulmak için hangi stratejiler ve araçlar yararlıdır?


152

10 yıldır C ++ yazdım. Bellek sorunları ile karşılaştım, ancak makul bir çaba ile düzeltilebilirler.

Son birkaç yıldır C # yazıyorum. Hâlâ çok fazla bellek problemim var. Belirleyici olmama nedeniyle teşhis etmek ve düzeltmek zordur ve C # felsefesi, kesinlikle yaptığınız zaman bu tür şeyler hakkında endişelenmenize gerek olmamasıdır.

Bulduğum özel bir sorun, açıkça bertaraf ve kod her şeyi temizlemek zorunda olmasıdır. Eğer yapmazsam, bellek profillerine gerçekten yardımcı olmaz, çünkü size göstermeye çalıştıkları tüm verilerde sızıntı bulamayacağınız çok fazla saman var. Acaba yanlış bir fikrim var mı yoksa sahip olduğum araç en iyisi mi?

.NET'te bellek sızıntılarıyla mücadelede ne tür stratejiler ve araçlar yararlıdır?


Yayınınızın başlığı yayınınızdaki soru ile gerçekten eşleşmiyor. Başlığınızı güncellemenizi öneririm.
Kevin

Haklısın. Üzgünüm, avladığım mevcut sızıntıdan biraz bıkmıştım! Başlık güncellendi.
Scott Langham

3
@Scott: .NET'ten bıkmayın, sorun değil. Kodunuz.
GEOCHET

3
Evet, kodumu veya üçüncü parti kütüphaneleri kullanmaktan zevk alıyorum.
Scott Langham

@Scott: Cevabımı gör. MemProfiler buna değer. Bunu kullanmak ayrıca size .NET GC dünyasını yepyeni bir şekilde anlayacaktır.
GEOCHET

Yanıtlar:


51

Bir bellek sızıntısı olduğundan şüphelendiğimde Scitech MemProfiler kullanıyorum .

Şimdiye kadar çok güvenilir ve güçlü buldum. Pastırmamı en az bir kez kurtardı.

GC, .NET IMO'da çok iyi çalışıyor, ancak diğer diller veya platformlar gibi, kötü kod yazarsanız, kötü şeyler olur.


3
Evet, bununla uğraştım ve bazı zor sızıntıların dibine ulaşmama yardımcı oldu. En büyük sızıntıların, birlikte çalışma yoluyla eriştikleri yönetilmeyen koddaki üçüncü taraf kütüphanelerinden kaynaklandığı ortaya çıktı. Bu aracın yönetilen kodun yanı sıra yönetilen kodda sızıntı tespit ettiği etkilendim.
Scott Langham

1
Bunu cevap olarak kabul ettim, çünkü sonunda benim için işe yarayan şeydi, ancak diğer tüm cevapların çok yararlı olduğunu düşünüyorum. Bu arada, bu araç daha çok SciTech'in Mem Profiler'ı olarak adlandırılıyor!
Scott Langham

41

Sadece atmayı unutma sorunu için, bu blog gönderisinde açıklanan çözümü deneyin . İşte özü:

    public void Dispose ()
    {
        // Dispose logic here ...

        // It's a bad error if someone forgets to call Dispose,
        // so in Debug builds, we put a finalizer in to detect
        // the error. If Dispose is called, we suppress the
        // finalizer.
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

#if DEBUG
    ~TimedLock()
    {
        // If this finalizer runs, someone somewhere failed to
        // call Dispose, which means we've failed to leave
        // a monitor!
        System.Diagnostics.Debug.Fail("Undisposed lock");
    }
#endif

Bunun yerine Debug.Fail bir istisna tercih ederim
Pedro77

17

Projemizde Red Gate yazılımıyla Ants Profiler Pro'yu kullandık . Tüm .NET dil tabanlı uygulamalar için gerçekten iyi çalışır.

.NET Çöp Toplayıcı'nın bellek içi nesneleri temizlemede çok "güvenli" olduğunu gördük (olması gerektiği gibi). Nesneleri , gelecekte bir süre kullanıyor olabileceğimiz için çevresinde tutacaktır . Bu, bellekte şişirdiğimiz nesne sayısı konusunda daha dikkatli olmamız gerektiği anlamına geliyordu. Sonunda, bellek yükünü azaltmak ve performansı artırmak için tüm veri nesnelerimizi "talep üzerine şişirmeye" dönüştürdük.

EDIT: İşte "talep üzerine şişirmek" ne demek istediğimi daha ayrıntılı bir açıklama. Veritabanımızın nesne modelimizde, alt nesneleri açıklamak için bir üst nesnenin Özelliklerini kullanırız. Örneğin, birebir bazda başka bir "detay" veya "arama" kaydına referansta bulunan bazı kayıtlarımız olsaydı, bunu şu şekilde yapılandırabiliriz:

class ParentObject
   Private mRelatedObject as New CRelatedObject
   public Readonly property RelatedObject() as CRelatedObject
      get
         mRelatedObject.getWithID(RelatedObjectID)
         return mRelatedObject
      end get
   end property
End class

Yukarıdaki sistemin, bellekte çok fazla kayıt olduğunda gerçek bellek ve performans sorunları yarattığını tespit ettik. Bu nedenle, nesnelerin yalnızca istendiğinde şişirildiği ve veritabanı çağrılarının yalnızca gerektiğinde yapıldığı bir sisteme geçtik:

class ParentObject
   Private mRelatedObject as CRelatedObject
   Public ReadOnly Property RelatedObject() as CRelatedObject
      Get
         If mRelatedObject is Nothing
            mRelatedObject = New CRelatedObject
         End If
         If mRelatedObject.isEmptyObject
            mRelatedObject.getWithID(RelatedObjectID)
         End If
         return mRelatedObject
      end get
   end Property
end class

Bu çok daha etkili olduğu ortaya çıktı çünkü nesneler ihtiyaç duyuluncaya kadar bellek dışında tutuldu (Get yöntemine erişildi). Veritabanı isabetlerini sınırlamada çok büyük bir performans artışı ve bellek alanında büyük bir kazanç sağladı.


Bu ürünü ikinciyim. Kullandığım en iyi profilcilerden biriydi.
Gord

Profil oluşturucuyu performans sorunlarına bakmak için oldukça iyi buldum. Ancak, bellek analiz araçları oldukça zayıftı. Bu araçla bir sızıntı buldum, ancak sızıntının nedenini tanımamda bana yardımcı oldu. Ve sızıntı yönetilmeyen kodda olursa size hiç yardımcı olmaz.
Scott Langham

Tamam, yeni sürüm 5.1, çok daha iyi bir halt. Sızıntının nedenini bulmanıza yardımcı olmak daha iyidir (yine de, ANTS'nin bir sonraki sürümde düzelteceklerini söylediği hala birkaç sorun vardır). Yine de yönetilmeyen kod yapmaz, ancak yönetilmeyen koddan rahatsız olmazsanız, bu oldukça iyi bir araçtır.
Scott Langham

7

Uygulamanız önemsiz olmadığı sürece yönetilen kod yazarken bellek konusunda endişelenmeniz gerekir. İki şey önereceğim: ilk olarak, C # üzerinden CLR okuyun çünkü .NET'te bellek yönetimini anlamanıza yardımcı olacaktır. İkinci olarak, CLRProfiler (Microsoft) gibi bir araç kullanmayı öğrenin . Bu, bellek sızıntısına neyin neden olduğu hakkında bir fikir verebilir (örneğin, büyük nesne yığını parçalanmanıza bir göz atabilirsiniz)


Evet. CLRPRofiler oldukça havalı. Size tahsis edilen nesnelerin verdiği görünümü kazmaya çalışırken bilgi ile biraz patlayıcı olabilir, ancak her şey orada. Kesinlikle iyi bir başlangıç ​​noktası, özellikle ücretsiz olarak.
Scott Langham

6

Yönetilmeyen kod kullanıyor musunuz? Yönetilmeyen kod kullanmıyorsanız, Microsoft'a göre, geleneksel anlamda bellek sızıntıları mümkün değildir.

Bununla birlikte, bir uygulama tarafından kullanılan bellek serbest bırakılamayabilir, bu nedenle bir uygulamanın bellek tahsisi uygulamanın ömrü boyunca büyüyebilir.

Gönderen Microsoft.com de ortak dil çalışma zamanı bellek sızıntılarını nasıl tanımlanır

Uygulamanın bir parçası olarak yönetilmeyen kod kullandığınızda bir .NET Framework uygulamasında bellek sızıntısı oluşabilir. Bu yönetilmeyen kod bellek sızdırabilir ve .NET Framework çalışma zamanı bu sorunu gideremez.

Ayrıca, bir projede yalnızca bellek sızıntısı var gibi görünebilir. Bu koşul, çok sayıda büyük nesne (DataTable nesneleri gibi) bildirilir ve bir koleksiyona (DataSet gibi) eklenirse oluşabilir. Bu nesnelerin sahip olduğu kaynaklar asla serbest bırakılmayabilir ve kaynaklar programın tüm çalışması için canlı bırakılabilir. Bu bir sızıntı gibi görünüyor, ama aslında bu sadece belleğin programda tahsis edilmesinin bir belirtisidir.

Bu tür sorunlarla uğraşmak için IDisposable uygulayabilirsiniz . Bellek yönetimi ile ilgili bazı stratejileri görmek istiyorsanız , oyun geliştiricilerinin daha öngörülebilir çöp toplamaya sahip olması ve böylece GC'yi işini yapmaya zorlaması gerektiği için IDisposable, XNA, bellek yönetimini aramanızı öneririm .

Sık karşılaşılan bir hata, bir nesneye abone olan olay işleyicilerini kaldırmamaktır. Olay işleyici aboneliği, bir nesnenin geri dönüştürülmesini önleyecektir. Ayrıca, bir kaynağın ömrü boyunca sınırlı bir kapsam oluşturmanıza olanak tanıyan using ifadesine bir göz atın .


5
Bkz. Blogs.msdn.com/tess/archive/2006/01/23/… . Bellek sızıntısının "geleneksel" olup olmadığı gerçekten önemli değil, hala bir sızıntı.
Constantin

2
Anladığım kadarıyla anlıyorum - ancak bir program tarafından belleğin verimsiz olarak tahsis edilmesi ve yeniden kullanılması bir bellek sızıntısından farklı.
Timothy Lee Russell

iyi cevap, olay işleyicilerin tehlikeli olabileceğini hatırladığınız için teşekkür ederim.
frameworkninja

3
@Timothy Lee Russel: İşe yaramaz hale geldikten sonra (2) sınırsız (1) miktarda bellek aynı anda tahsis edilebilirse (köklü) kalabilir, sistemde herhangi bir zamanda zamanında kök salmak için gerekli bilgi ve itici güce sahip olmadan, bu bir bellek sızıntısı . Bellek bir gün serbest bırakılabilse bile, bu gerçekleşmeden önce sistemi boğmak için yeterli işe yaramaz malzeme birikebilirse, bu bir sızıntıdır. (1) O (N) 'den büyük olan N, yararlı tahsis miktarıdır; (2) Referansların kaldırılması program işlevselliğini etkilemezse, şeyler işe yaramaz.
supercat

2
@Timothy Lee Russel: Normal "bellek sızıntısı" paterni, bellek artık bir tüzel kişi tarafından başka bir tüzel kişi adına tutulursa , artık gerekli olmadığında söylenmeyi beklerken ortaya çıkar; ancak ikincisi tüzel kişiyi ilkini bildirmeden terk eder. Belleği elinde tutan varlığın gerçekten ona ihtiyacı yoktur, ancak bunu belirlemenin bir yolu yoktur.
supercat

5

Bu blog , her türden bellek sızıntılarını izlemek için windbg ve diğer araçları kullanan gerçekten harika yollara sahiptir. Becerilerinizi geliştirmek için mükemmel okuma.


5

Ben sadece bir windows hizmetinde bir bellek sızıntı vardı, ben sabit.

İlk olarak MemProfiler'i denedim . Gerçekten kullanıcı dostu değil, kullanımı zor buldum.

Daha sonra, kullanımı daha kolay olan ve doğru şekilde atılmayan nesneler hakkında daha fazla ayrıntı veren JustTrace'i kullandım.

Bellek sızıntısını gerçekten kolayca çözebilmemi sağladı.


3

Gözlemlediğiniz sızıntılar kaçak bir önbellek uygulamasından kaynaklanıyorsa, bu WeakReference kullanımını düşünmek isteyebileceğiniz bir senaryodur . Bu, gerektiğinde belleğin serbest bırakılmasını sağlamaya yardımcı olabilir.

Bununla birlikte, IMHO ısmarlama bir çözümü düşünmek daha iyi olacaktır - nesneleri gerçekten ne kadar süre tutmanız gerektiğini gerçekten biliyorsunuz, bu nedenle durumunuz için uygun temizlik kodunu tasarlamak genellikle en iyi yaklaşımdır.


3

Jetbrains'den dotmemory'i tercih ederim


tek kişi siz olabilirsiniz :)
HellBaby

Ben de denedim. Bence bu iyi bir araç. Kullanımı kolay, bilgilendirici. Visual Studio ile bütünleşir
redeye

Bizim durumumuzda, bellek sızıntılarını giderirken, Visual Studio Anlık Görüntüsü aracı kilitlendi / anlık görüntü almadı. Dotmemory, serinliğini korudu ve (görünüşte) kolaylıkla 3+ GB'lik birden fazla anlık görüntü işledi.
Michael Kargl

3

Büyük silahlar - Windows için Hata Ayıklama Araçları

Bu inanılmaz bir araç koleksiyonudur. Hem yönetilen hem de yönetilmeyen yığınları bununla analiz edebilir ve çevrimdışı yapabilirsiniz. Bu, bellek aşırı kullanımı nedeniyle geri dönüşümü sağlayan ASP.NET uygulamalarımızdan birinde hata ayıklamak için çok kullanışlıdır. Üretim sunucusunda çalışan yaşam sürecinin tam bir bellek dökümü oluşturmak zorunda kaldım, tüm analizler WinDbg'de çevrimdışı yapıldı. (Bazı geliştiricilerin bellek içi Oturum depolamasını aşırı kullandıkları ortaya çıktı.)

"Eğer kırılırsa ..." blogunda bu konuda çok faydalı makaleler var.


2

Akılda tutulması gereken en iyi şey, nesnelerinize yapılan referansları takip etmektir. Artık umursadığınız nesnelere referanslar asmak çok kolaydır. Artık bir şey kullanmayacaksanız, ondan kurtulun.

İstenilen bir zaman aralığı için bir şeye başvurulmadığı takdirde, kaydı kaldırılacak ve temizlenecek şekilde kayan süreleri olan bir önbellek sağlayıcısı kullanmaya alışın. Ama çok fazla erişiliyorsa, bellekte söyleyecektir.


2

En iyi araçlardan biri, Windows için Hata Ayıklama Araçları'nı kullanmak ve adplus kullanarak sürecin bir bellek dökümü almaktır , daha sonra işlem belleğini, iş parçacıklarını ve çağrı yığınlarını analiz etmek için windbg ve sos eklentisini kullanın.

Araçları yükledikten, dizini paylaştıktan sonra (net kullanım) kullanarak sunucudan paylaşıma bağlanıp işlemin çökmesine veya askıda kalmasına neden olan bu yöntemi sunuculardaki sorunları tanımlamak için de kullanabilirsiniz.

Ardından çevrimdışı analiz edin.


Evet, bu özellikle de daha gelişmiş şeyler veya bir hata ayıklayıcıyı kolayca ekleyemediğiniz yayınlanmış yazılımlardaki sorunları teşhis etmek için iyi çalışır. Bu blogun bu araçları iyi kullanma konusunda birçok ipucu var: blogs.msdn.com/tess
Scott Langham

2

Yönetilen uygulama için yaptığım düzeltmelerden sonra, bir sonraki değişikliğimden sonra uygulamamın aynı bellek sızıntısına sahip olmayacağını nasıl doğrulayacağım gibi aynı şey vardı, bu yüzden Nesne Yayın Doğrulama çerçevesi gibi bir şey yazdım, lütfen bir göz atın NuGet paketi ObjectReleaseVerification . Bir örnek burada bulabilirsiniz https://github.com/outcoldman/OutcoldSolutions-ObjectReleaseVerification-Sample Bu numuneye ilişkin ve bilgi http://outcoldman.ru/en/blog/show/322


0

Visual Studio 2015'ten bellek kullanım verilerini toplamak ve analiz etmek için kutudan çıkarılmış Bellek Kullanımı tanılama aracını kullanmayı düşünün .

Bellek Kullanımı aracı, nesne türlerinin bellek kullanım etkisini anlamanıza yardımcı olmak için yönetilen ve yerel bellek yığınının bir veya daha fazla anlık görüntüsünü almanızı sağlar.


0

DotMemory'yi kullandığım en iyi araçlardan biri.Bu aracı VS'de bir uzantı olarak kullanabilirsiniz. uygulamanızı çalıştırdıktan sonra, uygulamanızın kullandığı belleğin her bir parçasını (Object, NameSpace vb. ile) analiz edebilir ve bunun anlık görüntüsünü alabilirsiniz. , Diğer SnapShots ile karşılaştırın. DotMemory

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.