2012-01-05 17 views
7

W tytule "Zmuszanie Colection śmieci" z książki "C# 2010 i platforma .NET 4" Andrew Troelsen napisane:Niepożądane Garbage Collection

„znowu całej celów .NET odśmiecaczem jest zarządzanie pamięcią w naszym imieniu, jednak w bardzo rzadkich przypadkach może być korzystne programowe wymuszenie zbierania śmieci za pomocą GC.Collect(). W szczególności:

• Twoja aplikacja wkrótce wejdzie w blok kodu, którego nie chcesz przerwać przez ewentualny wywóz śmieci. ... "

Ale zatrzymaj się! Czy istnieje taki przypadek, gdy zbieranie śmieci jest niepożądane? Nigdy nie widziałem/nie czytałem czegoś takiego (z uwagi na moje małe doświadczenie programistyczne oczywiście). Jeśli podczas praktyki zrobiłeś coś takiego, podziel się. Dla mnie jest to bardzo interesujący punkt.

Dziękujemy!

+7

Proszę wziąć pod uwagę * "bardzo rzadkie okoliczności" * i nie posypuj GC.Collect() całym kodem. –

+0

Będzie gotowe! :) – Arterius

Odpowiedz

5

Prowadzę stronę internetową związaną z recepturami, i przechowuję w pamięci ogromny wykres receptur i wykorzystania ich składników. Ze względu na sposób, w jaki obracam te informacje w celu szybkiego dostępu, muszę załadować kilka gigabajtów danych do pamięci, gdy aplikacja ładuje się, zanim będę mogła uporządkować dane na bardzo zoptymalizowanym wykresie. Tworzę ogromną liczbę małych obiektów na stercie, które po zbudowaniu wykresu stają się nieosiągalne.

Wszystko to dzieje się po załadowaniu aplikacji internetowej i prawdopodobnie zajmuje to 4-5 sekund. Po wykonaniu tej czynności zadzwonię pod numer GC.Collect();, ponieważ wolałbym teraz odzyskać całą tę pamięć, niż potencjalnie zablokować wszystkie wątki podczas przychodzącego żądania HTTP, podczas gdy narzędzie do usuwania nie działa, czyszcząc wszystkie te krótkotrwałe obiekty.Sądzę również, że lepiej jest teraz posprzątać, ponieważ sterta jest prawdopodobnie mniej rozdrobniona, ponieważ moja aplikacja tak naprawdę nie zrobiła nic więcej. Opóźnienie tego może spowodować utworzenie większej ilości obiektów, a sterta wymagająca większego skompresowania, gdy GC uruchomi się automatycznie.

Poza tym, w ciągu moich 12 lat programowania .NET, nigdy nie spotkałem się z sytuacją, w której chciałem wymusić uruchomienie garbage collectora.

7

Tak, jest absolutnie przypadek, gdy zbieranie śmieci jest niepożądane: gdy użytkownik czeka na coś, co może się wydarzyć, i muszą poczekać dłużej, ponieważ kod nie może być kontynuowany, dopóki nie zakończy się proces zbierania śmieci.

To punkt Troelsen za: jeśli masz konkretny punkt, w którym znasz GC nie jest problematyczne i jest prawdopodobne, aby móc gromadzić znaczne ilości śmieci to może być dobry pomysł, aby sprowokować następnie, aby uniknąć wywoływania w mniej dogodnym momencie.

+0

Wiesz, że to nie jest problematyczne, a nawet rzadsze niż scenariusze, w których możesz chcieć ... –

+0

@TonyHopkinson: Jest to stosunkowo rzadkie, ale niezauważalne. Dokładniej, możesz dobrze wiedzieć, że teraz jest * mniej * problematyczny, niż niedługo. –

+0

To zawsze jest powód, by łamać zasady, nie twierdząc, że nigdy nie powinieneś tego robić, tylko zanim je złamiesz, powinieneś je zrozumieć, abyś mógł je skutecznie złamać. –

1

Byłoby to bardzo rzadkie, ale GC może być procesem umiarkowanie drogim, więc jeśli istnieje określona sekcja, która jest wyczulona na czas, nie chcemy, aby ta sekcja była przerywana przez GC.

3

Zaleca się, aby nie wywoływać jawnie kodu Collect. Czy możesz znaleźć okoliczności, w których jest to przydatne?

Inne opisują niektóre i nie ma wątpliwości. Pierwszą rzeczą, którą należy zrozumieć, jest , nie rób tego. To ostatnia deska ratunku, sprawdź inne opcje, dowiedz się, jak działa GC, analizuj wpływ kodu, postępuj zgodnie ze sprawdzonymi metodami projektowania.

Zadzwoń pod Collect w niewłaściwym miejscu, co pogorszy Twoje wyniki. Co gorsza, poleganie na nim sprawia, że ​​twój kod jest bardzo delikatny. Rzadkie warunki wymagane do nawiązania połączenia z usługą Collect korzystne lub w końcu nieszkodliwe mogą zostać całkowicie cofnięte dzięki prostej zmianie kodu, co spowoduje nieoczekiwane OOM, powolną wydajność i takie.

2

Nazwałem to przed pomiarami wydajności, aby GC nie zafałszowało wyników.

Inna sytuacja to unit-testy testy wycieków pamięci:

object doesItLeak = /*...*/; //The object you want to have tested 
WeakReference reference = new WeakRefrence(doesItLeak); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

Assert.That(!reference.IsAlive); 

Poza tym, że nie wystąpi sytuacja, w której byłoby to rzeczywiście być pomocne.
W szczególności w kodzie produkcyjnym, GC.Collect nigdy nie powinno być znalezione IMHO.

1

Twoja aplikacja wkrótce przejdzie do bloku kodu, który nie zostanie przerwany przez możliwy proces czyszczenia pamięci. ...

Bardzo podejrzany argument (który jest jednak często używany).

Windows nie jest systemem czasu rzeczywistego. Twój kod (wątek/proces) zawsze może zostać uprzedzony przez program planujący systemu operacyjnego. Nie masz gwarantowanego dostępu do procesora.

Sprowadza się to do: w jaki sposób czas wykonania cyklu GC jest porównywalny z przedziałem czasowym (~ 20 ms)?

Jest bardzo mało dostępnych danych, przeszukałem kilka razy.

Z mojej własnej obserwacji (bardzo nieoficjalna), kolekcja gen-0 to < 40 ms, zwykle o wiele mniej. Pełny gen-2 może przebiegać w ~ 100 ms, prawdopodobnie więcej.

"Ryzyko" przerwania przez GC ma ten sam rząd wielkości co zamiana na inny proces. I nie możesz kontrolować tego drugiego.