2010-08-04 19 views
16

Mam witrynę ASP.NET, która osiągnie około 2 gb pamięci fizycznej używanej w ciągu około 3-4 dni, co dla mnie brzmi naprawdę źle. W tej chwili skonfigurowałem usługi IIS, aby ponownie uruchomić proces tworzenia puli aplikacji po osiągnięciu 500 MB. Chciałbym spróbować wyśledzić problem.Użycie pamięci ASP.NET dość wysokie

Podczas tworzenia nowej instancji obiektu w .NET, miałem wrażenie, że nie trzeba go zwolnić, ponieważ narzędzie do usuwania śmieci .NET zrobi to za mnie.

Czy tak jest, czy może to być jeden z powodów, dla których mam problemy?

+0

Co skonfigurował serwer z parametrem limitu czasu sesji? –

+0

Spojrzałem i widzę, że sesja dla mojej witryny jest ustawiona na "In Proccess" i nie ma limitu czasu w stosunku do pliku cookie asp, ale nie mogę znaleźć konkretnej sesji. Możesz doradzić? – webnoob

+0

To jest wiersz w moim pliku web.config dla sesji: - Wydaje się, że jest ustawiony na 20 minut. – webnoob

Odpowiedz

15

.NET bardzo efektywnie zarządza wyrzucaniem śmieci. W przypadku typów implementujących IDisposable dobrze jest wywołać metodę Dispose, prawdopodobnie nie jest to Twój problem. Przecieki pamięci mogą wystąpić w .NET z wielu powodów. Oto kilka:

  • Buforujesz za dużo danych na użytkownika w Sesji.
  • Buforujesz za dużo danych na poziomie aplikacji w pamięci podręcznej aplikacji lub w zmiennej statycznej, takiej jak słownik.
  • Możesz przechowywać formanty internetowe (lub kontrolki użytkownika) na poziomie sesji lub aplikacji.
  • Przechwytuje instancje do zdarzeń na typach statycznych lub do typów, które są przywoływane (ponieważ są przechowywane w pamięci podręcznej).

Mam nadzieję, że dzięki temu dowiesz się, gdzie szukać.

AKTUALIZACJA: Powinieneś obejrzeć this video o debugowaniu ASP.NET.

UPDATE 2: Twój komentarz na temat mojej odpowiedzi na następujące pytanie. CLR będzie zbierać wszystkie zarządzane pamięci, dlatego wszystkie obiekty utworzone przy użyciu new zostaną zebrane. W tym sensie nie ma znaczenia, czy obiekt implementuje IDisposable czy nie. Istnieje jednak wiele razy, że musisz użyć zasobów macierzystych (takich jak uchwyty plików, uchwyty graficzne, połączenia z bazami danych, wykorzystanie natywnej - tej niezarządzanej - pamięci) bezpośrednio lub pośrednio. Środowisko CLR nie wie, jak zwolnić te zasoby. Do tego .NET ma pojęcie finalizatorów. Finalizator to wirtualna metoda, którą może zaimplementować programista danej klasy. Gdy to zrobisz, CLR wywoła tę metodę po tym, jak tego typu instancja zostanie pozbawiona odwołań i zanim zostanie pobrana. Finalizery zazwyczaj zawierają logikę, która udostępnia te zasoby. Innymi słowy, gdy typ wymaga zasobów natywnych, zwykle ma on metodę finalizatora, która pozwala typowi zwolnić te zasoby.

Co dotyczy CLR, historia kończy się tutaj. CLR nie ma specyficznej obsługi obiektów, które implementują interfejs IDisposable. Odśmiecacz .NET ma jednak charakter nieokreślony. Oznacza to, że nie wiesz, kiedy działa i czy działa. Oznacza to, że może upłynąć sporo czasu zanim twoje natywne zasoby zostaną oczyszczone (ponieważ finalizator zostanie wywołany dopiero po pobraniu). W przypadku wielu zasobów konieczne jest jednak ich zwolnienie, gdy tylko skończysz z nimi. Na przykład często kończy się połączenie z bazą danych, gdy ich nie zamykasz lub gdy pracujesz z GDI + w .NET za pomocą przestrzeni nazw System.Drawing).

Z tego powodu wprowadzono interfejs IDisposable. Znowu CLR i garbage collector nie patrzą na ten interfejs. Jest to umowa między typem a jej użytkownikami, umożliwiająca użytkownikom bezpośrednie uwolnienie podstawowych zasobów obiektu. W normalnym projekcie zarówno finalizator obiektu, jak i metoda obiektu będą wywoływać tę samą prywatną lub chronioną metodę, która zwolni te zasoby. Gdy typ implementuje IDisposable, rozsądnie jest wywołać metodę Dispose po zakończeniu pracy lub zawinięciu obiektu w instrukcji using, aby zezwolić na determinację zasobów natywnych.

Powróć więc do pytania. Wszystkie zarządzane obiekty będą zbierane przez GC, ale zasoby natywne nie będą. Dlatego typy mogą implementować metodę finalizatora, a te obiekty będą również zwykle implementować interfejs IDisposable. Wywołanie na nich Dispose spowoduje jawne i bezpośrednie zwolnienie tych zasobów macierzystych.

Mam nadzieję, że to ma sens.

+0

Czy to oznacza, że ​​tylko klasy dziedziczące z IDisposable będą GC'd? – webnoob

+0

@Webnoob: zobacz moją aktualizację. – Steven

+0

Myślę, że właśnie znalazłeś przyczynę mojego problemu :) Wszystkie obrazy na mojej stronie są uruchamiane przez niestandardowy handler, który napisałem, który tworzy miniaturę tego obrazu. Z tego, co pamiętam, nie robię niczego, co można wyczyścić na tym kodzie i zdecydowanie używa metod system.drawing. Świetne miejsce, by zacząć dla mnie. Dzięki za post. Oznaczyłem to jako odpowiedź, ponieważ daje mi najwięcej informacji, których potrzebuję w tej chwili. – webnoob

6

Może być wiele przyczyn wysokiego zużycia pamięci, ale funkcja Garbage Collection w .NET jest bardzo precyzyjna. To znaczy, że wiele dla ciebie, ale czasami nie tak dużo, jak byś się spodziewał.

W szczególności może usuwać tylko obiekty, do których nie ma aktywnych referencji, więc jeśli skończysz z klasą, ale coś wciąż ma do niej odniesienie, zechcesz ją usunąć, aby GC może odzyskać tę pamięć dla ciebie. Dodatkowo, jeśli masz jakieś nieaktywne otwarte połączenia (powiedzmy, do DB lub coś podobnego) nie zapomnij zamknąć i wyrzucić je. Zazwyczaj możemy owinąć takich obiektów w using bloków tak:

using(SqlConnection conn = new SqlConnection(myConnString)) 
{ ...rest of code here } 

ten zamknie się automatycznie i rozporządzania połączenia; Jestem całkiem pewny, że to również sprawia, że ​​próbujesz/wreszcie za darmo (ktoś mi to w dupcie, proszę).

Poza tym, odpowiedź brzmi "profil, profil, profil", dopóki nie znajdziesz wycieku/wąskiego gardła/cokolwiek.

+1

+1 dla profilu profilu profilu –

+1

Tak, użycie instrukcji 'using' jest równoważne użyciu bloku' try' -finally' z wywołaniem 'Dispose' w bloku' finally'. – Steven

+0

@Steven: Dzięki za to. – AllenG

0

Podczas gdy prawdą jest, że nie musisz jawnie zwalniać pamięci, a odśmiecacz zrobi to za ciebie, możliwe jest, że kod nieumyślnie przytrzymuje odniesienie do obiektu, aby zapobiec jego zebraniu - jest to zasadniczo wyciek pamięci.

Obiekty ASP.NET pozostają "żywe", gdy są przywoływane przez pamięć podręczną aplikacji i sesji. Nie wiedząc nic o swojej aplikacji, proponuję uzyskać profiler pamięci i przyjrzeć się dokładniej temu, co jest w pamięci i czy pamięć podręczna aplikacji lub sesji trzyma coś, czego nie powinna.

1

Przecieki pamięci w .NET są nadal możliwe. Prawdą jest, że w przeważającej części nie trzeba zwolnić obiektów (jest kilka wyjątków, takich jak obiekt Graphics), ale jeśli zachowacie odnośniki do nich, nie będą zbierać śmieci, ponieważ są one nadal przywoływane.

Jeśli GC zauważy, że obiekt jest przywoływany gdziekolwiek, w dowolnym miejscu w aplikacji, nie będzie go kosza.

Zapoznaj się z tym artykułem o błędach pamięci .NET oraz o tym, jak je zlokalizować i naprawić.

2

Istnieje kilka rzeczy, które należy szukać w:

Przede wszystkim używasz sesje? Czy są to sesje proc lub SQL? Jeśli są w trakcie, to w jakim limicie czasu jest ustawiony? Jeśli masz naprawdę długi czas oczekiwania, może to wyjaśnić, dlaczego używasz tak dużo pamięci (sesje użytkownika będą przechowywane przez długi czas).

Po drugie, usuwanie przedmiotów. The.NET garbage collector pozbywa się referencji dla ciebie, ale kiedy tworzysz obiekty implementujące interfejs IDisposable, powinieneś zawsze używać słowa kluczowego using.

using(Foo foo = new Foo()) 
{ 
    ... 
} 

jest odpowiednikiem robi:

Foo foo; 
try 
{ 
    foo = new Foo(); 
    ... 
} 
finally 
{ 
    foo.Dispose(); 
} 

I będzie upewnić się, że dysponowania obiektami sprawnie.

Jeśli nadal nie można znaleźć niczego oczywistego w kodzie, można go profilować, zaczynając od metod, które są nazywane najczęściej. Możesz znaleźć informacje na temat dobrych profilerów here. To z pewnością doprowadzi cię do źródła twojego problemu.

1

Jeśli aplikacja ASP.NET korzysta z zdarzeń (i których nie ma), then you have to make sure you unsubscribe from the event.

Zasada:

Jeśli używasz += subskrybować zdarzenia, następnie trzeba użyć -= w metodzie Dispose() wypisać.

Istnieje lotsofresourceson this topic i miałem trochę bólu w aplikacjach Pracowałem już w ponieważ run-of-the-mill programista nie zdaje sobie sprawy, że zdarzenia mogą spowodować wycieki pamięci.

+0

W większości przypadków rezygnacja z subskrypcji jest niepotrzebna. Jest potrzebny tylko wtedy, gdy subskrybujesz wydarzenie na długo żyjącym obiekcie. Zdarzenia między krótkimi obiektami, takimi jak kontrolki na pojedynczej stronie, nie wymagają ręcznego czyszczenia: http: // stackoverflow.com/questions/345130/do-i-need-to-unsubscribe-from-manual-subscribed-to-events-in-asp-net –

1

Użyj memory profiler (na zrzucie pamięci lub w środowisku na żywo), gdy pamięć przekracza 500 MB, aby uzyskać wskazówkę, które obiekty zajmują całe to miejsce.

Podczas profilowania w środowisku programistycznym możesz zauważyć, że jeden typ obiektu rośnie tylko podczas przeglądania witryny, podczas gdy inne pozostają globalnie takie same.

Powiązane problemy