Opracowujemy dość dużą aplikację Windows Forms. Na komputerach kilku klientów często zawiesza się z wyjątkiem OutOfMemory. Po uzyskaniu pełnego zrzutu pamięci aplikacji po wystąpieniu wyjątku (clrdump wywołany z obsługi UnhandledException) przeanalizowałem go za pomocą ".NET Memory Profiler" i windbg.OutOfMemory, ale bez gcroots dla wielu obiektów
Profiler pamięci pokazał tylko 130 MB w instancjach obiektów na żywo. Co ciekawe, dla wielu typów obiektów pokazano bardzo dużą liczbę nieosiągalnych instancji (np. 22000 nieosiągalnych instancji Byte []). W statystykach pamięci rodzimej wartość ta wynosi 127 MB we wszystkich stertach dla danych (co jest w porządku), ale wskazuje nieosiągalne 133 MB w sterty nr 2 i 640 MB w dużej sterty (nie jest dobrze!).
Analizując zrzut z WinDbg, powyższe statystyki są potwierdzone:
!dumpheap -stat
..... acceptable object sizes...
79330a00 467216 30638712 System.String
0016d488 4804 221756612 Free
79333470 27089 574278304 System.Byte[]
Aplikacja robi użyć dużej liczby krótkich buforów poprzez swój bieg czasu, ale ich nie przeciekać. Testowanie wielu instancji Byte [] przy pomocy! Gcroot kończy się bez korzeni. Oczywiście większość z tych tablic jest nieosiągalna, jak wskazuje profiler pamięci.
Wystarczy, aby upewnić się, wszystko jest w porządku,! Finalizequeue pokazuje żadne przedmioty czekają zostać sfinalizowane
generation 0 has 138 finalizable objects (18bd1938->18bd1b60)
generation 1 has 182 finalizable objects (18bd1660->18bd1938)
generation 2 has 75372 finalizable objects (18b87cb0->18bd1660)
Ready for finalization 0 objects (18bd1b60->18bd1b60)
a także sprawdzić na rodzimym śladu wątek finalizator stosu pokazuje, że nie jest zablokowany.
W tej chwili nie, jak zdiagnozować dlaczego GC nie zbiera dane (i wierzę, że to lubią, ponieważ proces zabrakło pamięci ..)
edit: Based na wejściu poniżej czytałem trochę więcej na temat rozdrobnienia dużych obiektów i wydaje się, że tak być może.
Widziałem kilka rad, aby przydzielić większe bloki pamięci dla tego rodzaju danych (różne bajty [] w moim przypadku) i zarządzać pamięcią w tym obszarze przeze mnie, ale wydaje się to raczej raczej hackowskim rozwiązaniem, a nie jeden z nich spodziewałbym się rozwiązać problem z niezbyt specjalną aplikacją komputerową.
Problem fragmentacji spowodowany jest faktem (Przynajmniej tyle osób z Microsoftu pisze na blogach), że przedmioty na LOH nie są przenoszone w czasie istnienia, co jest zrozumiałe, ale wydaje się logiczne, że gdy pewne ciśnienie pamięci jest osiągnięte, takie jak groźba uzyskania OOM, należy przeprowadzić przeniesienie.
Jedyne, co mnie martwi, zanim w pełni ufa, że przyczyną jest fragmentacja, jest to, że tak wiele obiektów na LOH jest bez odniesień gcroot - czy to dlatego, że nawet w przypadku zbierania śmieci LOH wykonywane są tylko częściowo?
Z przyjemnością wskażę mi jakieś ciekawe rozwiązanie, ponieważ w tej chwili jedyne, co znam, to niestandardowe zarządzanie niektórymi blokami pamięci.
Wszelkie pomysły są mile widziane. Dzięki.
Bufory różnią się od 20k do kilku MB i zwykle są tworzone przez dostawcę bazy danych, aby załadować dane do postaci db lub nasz kod, który następnie wypełnia je danymi z gniazda (rozmiar danych jest znany, więc definiowane są bufory z prawidłowym rozmiarem, nie rosną) – grepfruit
Czy są znane wielkości w czasie wykonywania lub designtime? Wygląda na to, że będziesz musiał znaleźć sposób na ich ponowne wykorzystanie. –
Rozmiar jest ustalany w czasie wykonywania - elementy pamięci MIME w buforze przechowują wiadomości e-mail, więc każdy bufor różni się rozmiarem. Możemy próbować ponownie użyć naszych własnych buforów, ale są też bufory od dostawcy. Ale tak, w tej chwili będziemy musieli spróbować ponownie wykorzystać część bufora. Chociaż to tylko opóźni problem, uważam .. – grepfruit