Najlepszą praktyką jest nie wymuszanie wyrzucania elementów bezużytecznych.
Według MSDN:
„Można wymusić wyrzucanie elementów bezużytecznych przez wywołanie funkcji Collect, ale w większości przypadków należy tego unikać, ponieważ może to powodować problemy z wydajnością”.
Jeśli jednak możesz niezawodnie przetestować swój kod, aby potwierdzić, że wywołanie Collect () nie będzie miało negatywnego wpływu, kontynuuj ...
Po prostu postaraj się, aby obiekty zostały wyczyszczone, gdy już ich nie potrzebujesz. Jeśli masz obiekty niestandardowe, skorzystaj z instrukcji „using” i interfejsu IDisposable.
Ten link zawiera kilka dobrych praktycznych porad dotyczących zwalniania pamięci / czyszczenia pamięci itp .:
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
TargetOfInvocationNullException
.Spójrz na to w ten sposób - czy efektywniej jest wyrzucać śmieci kuchenne, gdy poziom kosza na śmieci wynosi 10%, czy też pozwolić mu się zapełnić przed wyjęciem?
Nie pozwalając mu się zapełnić, tracisz czas na chodzenie do i z kosza na śmieci na zewnątrz. Jest to analogiczne do tego, co dzieje się, gdy działa wątek GC - wszystkie zarządzane wątki są zawieszane, gdy jest uruchomiony. I jeśli się nie mylę, wątek GC może być współużytkowany przez wiele domen AppDomains, więc czyszczenie pamięci wpływa na wszystkie z nich.
Oczywiście możesz spotkać się z sytuacją, w której w najbliższym czasie nie będziesz niczego dodawać do kosza - powiedzmy, jeśli wybierasz się na wakacje. Wtedy dobrze byłoby wyrzucić śmieci przed wyjściem.
MOŻE to być jeden raz, kiedy wymuszenie GC może pomóc - jeśli twój program jest bezczynny, używana pamięć nie jest usuwana z pamięci, ponieważ nie ma przydziałów.
źródło
W większości przypadków najlepszym rozwiązaniem jest niewymuszanie wyrzucania elementów bezużytecznych. (Każdy system, nad którym pracowałem, wymuszał zbieranie śmieci, miał podkreślane problemy, których rozwiązanie wyeliminowałoby potrzebę wymuszania zbierania śmieci i znacznie przyspieszyło system.)
Jest kilka przypadków , w których wiesz więcej na temat użycia pamięci niż garbage collector. Jest to mało prawdopodobne w przypadku aplikacji dla wielu użytkowników lub usługi, która odpowiada na więcej niż jedno żądanie naraz.
Jednak w niektórych procesach wsadowych wiesz więcej niż GC. Np. Rozważ taką aplikację.
Państwo może być w stanie dokonać przypadek (po ostrożnym) badania, które powinny wymusić pełną kolekcję śmieci po trzeba przetworzyć każdy plik.
Innym przypadkiem jest usługa, która budzi się co kilka minut w celu przetworzenia niektórych elementów i nie utrzymuje żadnego stanu podczas snu . Następnie zmuszając pełną kolekcję tuż przed pójściem spać może się opłacać.
Wolałbym mieć API do zbierania śmieci, kiedy mógłbym dać mu wskazówki na temat tego typu rzeczy bez konieczności wymuszania GC samodzielnie.
Zobacz też „ Ciekawostki o występach Rico Marianiego ”
źródło
Myślę, że przykład podany przez Rico Marianiego był dobry: wszczęcie GC może być właściwe, jeśli nastąpi znacząca zmiana w stanie aplikacji. Na przykład w edytorze dokumentów może być OK, aby wyzwolić GC, gdy dokument jest zamknięty.
źródło
Istnieje kilka ogólnych wskazówek dotyczących programowania, które są bezwzględne. W połowie przypadków, gdy ktoś mówi „robisz to źle”, po prostu wypowiada pewną ilość dogmatów. W C dawniej obawiał się rzeczy, takich jak samomodyfikujący się kod lub wątki, w językach GC wymusza GC lub alternatywnie uniemożliwia uruchomienie GC.
Podobnie jak w przypadku większości wytycznych i dobrych reguł praktycznych (oraz dobrych praktyk projektowych), są rzadkie sytuacje, w których warto obejść ustaloną normę. Musisz być bardzo pewien, że rozumiesz sprawę, że Twój przypadek naprawdę wymaga zniesienia powszechnej praktyki i że rozumiesz ryzyko i skutki uboczne, które możesz spowodować. Ale są takie przypadki.
Problemy programistyczne są bardzo zróżnicowane i wymagają elastycznego podejścia. Widziałem przypadki, w których ma sens blokowanie GC w językach ze śmieciami oraz w miejscach, w których ma sens, aby go wywołać, zamiast czekać, aż pojawi się naturalnie. W 95% przypadków którykolwiek z nich byłby drogowskazem, wskazującym na niewłaściwe podejście do problemu. Ale 1 raz na 20 prawdopodobnie istnieje uzasadniona argumentacja.
źródło
Nauczyłem się, aby nie próbować przechytrzyć zbierania śmieci. Mając to na uwadze, po prostu trzymam się
using
słowa kluczowego, gdy mam do czynienia z niezarządzanymi zasobami, takimi jak we / wy plików lub połączenia z bazami danych.źródło
Nie jestem pewien, czy jest to najlepsza praktyka, ale podczas pracy z dużą ilością obrazów w pętli (tj. Tworząc i usuwając wiele obiektów Graphics / Image / Bitmap), regularnie pozwalam GC.Collect.
Myślę, że gdzieś przeczytałem, że GC działa tylko wtedy, gdy program jest (w większości) bezczynny, a nie w środku intensywnej pętli, więc może to wyglądać jak obszar, w którym ręczny GC mógłby mieć sens.
źródło
Niedawno spotkałem się z przypadkiem, który wymagał ręcznego wywołania,
GC.Collect()
gdy pracowałem z dużymi obiektami C ++, które były opakowane w małe zarządzane obiekty C ++, do których z kolei dostęp był uzyskiwany z C #.Moduł odśmiecania pamięci nigdy nie został wywołany, ponieważ ilość używanej pamięci zarządzanej była znikoma, ale ilość używanej pamięci niezarządzanej była ogromna. Ręczne wywoływanie
Dispose()
obiektów wymagałoby ode mnie śledzenia, kiedy obiekty nie są już potrzebne, podczas gdy wywołanieGC.Collect()
spowoduje wyczyszczenie wszystkich obiektów, do których już nie istnieją odniesienia .....źródło
GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource)
konstruktora, a późniejGC.RemoveMemoryPressure(addedSize)
finalizatora. W ten sposób garbage collector będzie działał automatycznie, biorąc pod uwagę rozmiar niezarządzanych struktur, które można zebrać. stackoverflow.com/questions/1149181/…Myślę, że wymieniłeś już najlepsze praktyki i NIE jest to używanie ich, chyba że NAPRAWDĘ jest to konieczne. Zdecydowanie zaleciłbym przyjrzenie się kodowi bardziej szczegółowo i użycie narzędzi do profilowania, jeśli zajdzie taka potrzeba, aby najpierw odpowiedzieć na te pytania.
źródło
Załóżmy, że Twój program nie ma wycieków pamięci, obiekty gromadzą się i nie mogą być poddane GC w Gen 0, ponieważ: 1) Są przywoływane przez długi czas, więc przejdź do Gen1 i Gen2; 2) Są to duże obiekty (> 80K), więc wejdź do LOH (Large Object Heap). A LOH nie wykonuje kompaktowania, jak w Gen0, Gen1 i Gen2.
Sprawdź licznik wydajności ".NET Memory" i widzisz, że problem 1) naprawdę nie jest problemem. Ogólnie rzecz biorąc, każde 10 GC Gen0 wyzwala 1 GC Gen1, a każde 10 GC Gen1 wyzwala 1 GC Gen2. Teoretycznie GC1 i GC2 nigdy nie mogą być poddane GC, jeśli nie ma nacisku na GC0 (jeśli użycie pamięci programu jest naprawdę podłączone). Nigdy mi się to nie przytrafiło.
W przypadku problemu 2) można sprawdzić licznik wydajności „.NET Memory”, aby sprawdzić, czy LOH nie jest nadęty. Jeśli naprawdę stanowi to problem, być może możesz utworzyć pulę dużych obiektów, jak sugeruje ten blog http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx .
źródło
Duże obiekty są przydzielane na LOH (sterta dużych obiektów), a nie na gen. 0. Jeśli mówisz, że nie są zbierane śmieci z genem 0, masz rację. Uważam, że są zbierane tylko wtedy, gdy nastąpi pełny cykl GC (generacja 0, 1 i 2).
Biorąc to pod uwagę, uważam, że z drugiej strony GC będzie dostosowywać i gromadzić pamięć bardziej agresywnie, gdy pracujesz z dużymi obiektami, gdy ciśnienie pamięci rośnie.
Trudno powiedzieć, czy zbierać, czy nie iw jakich okolicznościach. Kiedyś robiłem GC.Collect () po usunięciu okien dialogowych / formularzy z licznymi kontrolkami itp. (Ponieważ do czasu, gdy formularz i jego kontrolki kończą się w Gen 2 z powodu tworzenia wielu instancji obiektów biznesowych / ładowania dużej ilości danych - nie oczywiście duże obiekty), ale w dłuższej perspektywie nie zauważył żadnych pozytywnych ani negatywnych skutków.
źródło
Dodam, że: Wywołanie GC.Collect () (+ WaitForPendingFinalizers ()) to jedna część historii. Jak słusznie wspomnieli inni, GC.COllect () jest kolekcją niedeterministyczną i jest pozostawiona uznaniu samego GC (CLR). Nawet jeśli dodasz wywołanie do WaitForPendingFinalizers, może nie być deterministyczne. Weź kod z tego linku msdn i uruchom kod z iteracją pętli obiektów na 1 lub 2. Dowiesz się, co oznacza niedeterministyczne (ustaw punkt przerwania w destruktorze obiektu). Dokładniej, destruktor nie jest wywoływany, gdy był tylko 1 (lub 2) obiekt pokutujący przez Wait .. (). [Citation reqd.]
Jeśli Twój kod ma do czynienia z niezarządzanymi zasobami (np. Zewnętrznymi uchwytami plików), musisz zaimplementować destruktory (lub finalizatory).
Oto ciekawy przykład:
Uwaga : Jeśli już wypróbowałeś powyższy przykład z MSDN, następujący kod oczyści powietrze.
Sugeruję, najpierw przeanalizuj, jakie może być wyjście, a następnie uruchom, a następnie przeczytaj przyczynę poniżej:
{Destruktor jest wywoływany niejawnie dopiero po zakończeniu programu. } Aby deterministycznie wyczyścić obiekt, należy zaimplementować IDisposable i wykonać jawne wywołanie metody Dispose (). To jest istota! :)
źródło
Jeszcze jedno, jawne uruchomienie GC Collect może NIE poprawić wydajności programu. Całkiem możliwe, że będzie gorzej.
NET GC jest dobrze zaprojektowany i dostrojony do adaptacji, co oznacza, że może dostosować próg GC0 / 1/2 zgodnie z „nawykiem” wykorzystania pamięci programu. Tak więc po pewnym czasie zostanie dostosowany do twojego programu. Po jawnym wywołaniu GC.Collect progi zostaną zresetowane! A .NET musi poświęcić trochę czasu na ponowne przystosowanie się do „nawyków” programu.
Moja sugestia jest zawsze zaufana .NET GC. Pojawią się jakiekolwiek problemy z pamięcią, sprawdź licznik wydajności „.NET Memory” i zdiagnozuj mój własny kod.
źródło
Sugestia: nie wdrażaj tego ani niczego, jeśli nie masz pewności. Dokonaj ponownej oceny, gdy znane są fakty, a następnie przeprowadź testy wydajności przed / po, aby zweryfikować.
źródło
IMHO, jest to podobne do powiedzenia „Jeśli możesz udowodnić, że Twój program nigdy nie będzie zawierał żadnych błędów w przyszłości, to śmiało ...”
Mówiąc poważnie, wymuszanie GC jest przydatne do debugowania / testowania. Jeśli czujesz, że musisz to zrobić w innym czasie, albo się mylisz, albo Twój program został źle zbudowany. Tak czy inaczej, rozwiązaniem nie jest wymuszenie GC ...
źródło