2009-03-02 6 views
13

Ten problem prowadzi do kłującego problemu z naszą aplikacją internetową. (Serwer Asp.net 2.0 Win 2008)Obiekt nie jest zbiorem śmieci, ale nie zawiera elementów gcroot

Nasze wykorzystanie pamięci dla strony internetowej rośnie i rośnie, chociaż spodziewam się, że pozostanie na dość statycznym poziomie. (Mamy niewielką ilość danych, które są przechowywane w stanie).

Chcąc dowiedzieć się, na czym polega problem, uruchomiłem System.GC.Collect(); kilka razy, wziął zrzut pamięci, a następnie załadował ten zrzut pamięci do WinDbg.

Kiedy robię DumpHeap -Stat, otrzymuję niezmiernie dużą liczbę na konkretnym typie, zawieszoną w pamięci.

0000064280580b40 713471 79908752 PaymentOption

tak, robi DumpHeap -MT dla tego typu, mam stos odniesień do obiektu. Wybierając ich losową liczbę, robię a! Gcroot, a polecenie wraca, informując, że nie ma do nich żadnych odniesień.

Dla mnie to właśnie wtedy GC powinien zbierać te przedmioty, ale z jakiegoś powodu zostały one zaległe.

Czy ktoś może wyjaśnić, co może się wydarzyć?

+0

Chciałbym zobaczyć, czy kiedykolwiek to rozwiązałeś ... – womp

+1

Niestety nie. Doszliśmy do obejścia tego problemu, recyklingując proces, gdy użyjemy więcej niż nGB pamięci, co pozwoliło na inne procesy. Podejrzewam, że jest to problem z fragmentacją i nowym przydziałem pamięci. Wkrótce przeprowadzę dalsze dochodzenie, więc opublikuję aktualizację. – Lachmania

Odpowiedz

1

Nie bez dodatkowych informacji o aplikacji. Ale już dawno temu natknęliśmy się na pewne problemy z pamięcią. Czy używasz buforowania ASP.NET? Jak lubi Raymond Chen, "słaba strategia buforowania jest nieodłączna od wycieku pamięci".

Sprawdź inne narzędzie - CLRProfiler.exe - pomoże ci przejść drzewko referencji do obiektów, aby zobaczyć, gdzie znajdują się Twoje obiekty. Jest to również dobre: ​​link text

Słyszeliście to już wcześniej - jeśli macie GC.Collect, coś jest nie tak.

+0

Bez buforowania, co jest dziwną rzeczą, która się tutaj dzieje. Mamy komponent do raportowania innej firmy, który z jakiegoś powodu korzysta z pamięci podręcznej (można powiedzieć o gcrootach, które ma) – Lachmania

+0

Dzięki za podpowiedź na CLRProfiler, ale problem polega na tym, że gdy TraverseHeap jest tworzony i zapisywany jest xml, przedmioty, które mnie interesują, nie istnieją. (Tego właśnie mogłem się spodziewać, ponieważ wygląda na to, że nie mają one żadnych ważnych korzeni). – Lachmania

+0

Aby było jasne, mam przycisk, który wywołuje GC.Zbierz, że kilka razy wciskam przed zrobieniem zrzutu pamięci, to nie dostanie połączenia podczas normalnej pracy. – Lachmania

1

Czy przypadkiem jest obiekt PaymentOption utworzony w procesie asynchronicznym? Pamiętam coś o, jeśli nie zadzwonisz do EndInvoke, możesz dostać takie problemy.

2

kilka rzeczy:

  1. GC.Collect nie pomoże ci robić żadnych debugowanie. Śmieciarz jest już wywoływany: gdyby jakiekolwiek obiekty były dostępne do pobrania, już by to się stało.
  2. Idle pamięć na serwerze to zmarnowana pamięć. Czy na pewno pamięć jest "wyciekła", czy też po prostu struktura decyduje, że może przechowywać więcej rzeczy w pamięci lub mieć więcej pamięci dla szybszego dostępu? W tym przypadku podejrzewam, że masz przeciekającą pamięć, ale warto to sprawdzić.
  3. Brzmi jak coś, czego się nie spodziewasz, to odwoływanie się do obiektów PaymentOption. Być może gdzieś znajduje się kolekcja statyczna? Lub oddzielny wątek?
+1

pt2: Zgadzam się, że bezczynna pamięć jest marnowana, ale widzę występy pamięci RAM używane na obiektach, które nie są zrootowane, ale nie wydają się zbierane. – Lachmania

+1

pt3: Podejrzewam, że to właśnie się dzieje, ale! Gcroot nie zgłasza żadnych odniesień, nie jestem pewien, gdzie się dowiedzieć, co może ich zatrzymać. Chyba to jest sedno mojego pytania. – Lachmania

+0

Wiem, że to już jest stare, ale chciałem dodać coś, co mi się przydarzyło i nie jest wspomniane nigdzie indziej w pytaniu. Może to być duża kupa obiektu. Jeśli jest szansa, że ​​obiekty te mają> 80 000 bajtów, możesz mieć z tym problem. –

4

Możesz spróbować użyć sosex.dll w Windbg, który jest rozszerzeniem napisanym do pomocy przy debugowaniu .NET. Istnieje polecenie o nazwie! Refs, które jest podobne do! Gcroot, ponieważ pokaże ci wszystkie obiekty odwołujące się do obiektu, a także pokaże wszystkie obiekty, do których się odwołuje.

W przykładzie na stronie autora,!Sędziowie są wykorzystywane przeciwko obiektu i wyjście wygląda następująco:

0:000> !refs 0000000080000db8 
Objects referenced by 0000000080000db8 (System.Threading.Mutex): 
0000000080000ef0   32 Microsoft.Win32.SafeHandles.SafeWaitHandle 

Objects referencing 0000000080000db8 (System.Threading.Mutex): 
0000000080000e08   72 System.Threading.Mutex+<>c__DisplayClass3 
0000000080000e50   64 System.Runtime.CompilerServices.RuntimeHelpers+CleanupCode 
+0

Dzięki za cynk. Ale już to sprawdziłem i nie dostałem żadnej miłości od polecenia! Refs. Nie zgłosiło żadnych korzeni. grrr – Lachmania

1

Byłem bada ten sam problem siebie i pytał dlaczego obiekty, które nie miały odniesienia nie były zbierane.

obiektów większych niż 85000 bajtów przechowywany na dużych Heap obiektu, z którego pamięci uwolnionych mniej często.

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

Pojedyncza PaymentOption nie mogą być duże, ale są one zawarte w zbiorach, lub są one oparte na czymś takim DataSet? Powinieneś wybrać kilka instancji PaymentOption/collection/DataSet, a następnie użyć polecenia sos! Objsize, aby zobaczyć, jakie są duże.

Niestety ten produkt nie odpowiedzieć na pytanie. Lubię wierzyć, że mogę zaufać środowisku .net, aby zająć się uwalnianiem nieużywanej pamięci w dowolnym momencie. Jednak widzę, że wiele pamięci jest używane przez proces roboczy, na którym działa aplikacja, na którą patrzę, nawet jeśli pamięć wygląda dość ciasno na serwerze.

2

Does PaymentObject wdrożyć finalizatora przypadkiem? Czy wywołuje obiekt STA COM?

Chciałbym zobaczyć wyjście! Finalizequeue, aby zobaczyć, czy liczba obiektów wyświetlanych na stercie to w przybliżeniu ilość obiektów, które mogą czekać na sfinalizowanie. Wyjście prawdopodobnie powinien wyglądać mniej więcej tak:

generation 0 has 57 finalizable objects (0409b5cc->0409b6b0) 
generation 1 has 55 finalizable objects (0409b4f0->0409b5cc) 
generation 2 has 0 finalizable objects (0409b4f0->0409b4f0) 
Ready for finalization 0 objects (0409b6b0->0409b6b0) 

Jeżeli liczba Gotowy do finalizacji obiektów nadal rośnie, a twoje pewne zbiory śmieci są występujące (potwierdzenie poprzez Perfmon liczników), to może to być zablokowane finalizator wątek. Może być konieczne wykonanie kilku migawek przez cały okres trwania procesu (przed ponownym przetworzeniem) w celu potwierdzenia. Zwykle polegam na magicznej liczbie trzech, o ile strona jest pod jakimś obciążeniem.

Błąd w finalizatora może zablokować nić finalizatora i zapobiegania obiektów od zawsze zbierano.

Jeśli obiekt PaymentOption wywoła poprzedni obiekt STA COM, artykuł ASP.NET Hang and OutOfMemory exceptions caused by STA components może wskazywać właściwy kierunek.

0

FYI, SOS w .NET 4 obsługuje kilka nowych poleceń, które mogą być pomocne, a mianowicie !gcwhere (zlokalizować generację sprzeciwu; gcgen sosex) i !findroots (robi to, co mówi na opakowaniu;! Sosex na pozycje literaturowe)

Obie są udokumentowane na SOS documentation i mentioned on Tess Ferrandez's blog.

Powiązane problemy