Wątek przeniesiony 2018-07-31 10:08 z Newbie przez somekind.

Dlaczego GC zatrzymuje aktywne wątki?

0

W książce, którą czytam, jest napisane, że aby ensure that the application does not access the managed heap during the collection process. Czy mógłby ktoś napisać coś więcej? Dlaczego wątki nie mogą alokować nowych obiektów w czasie trwania kolekcji, dopóki jest miejsce na stercie?

2

Ponieważ nowe obiekty mogą zawierać referencje do starych obiektów, które GC już oznaczył jako nieosiągalne. Stąd, przy naiwnym rozwiązaniu, graf musiałby być poprawiany przy każdej alokacji, a wszystkie referencje musiałyby być atomowe. Jakoś lepiej trzeba ten problem rozwiązać. Większość dotychczasowych GC rozwiązuje to przez zatrzymanie wszystkich wątków użytkownika, ale są GC które pozwalają wątkom użytkownika działać podczas większości procesu odśmiecania. Dla Javy to np:
http://openjdk.java.net/projects/shenandoah/
http://openjdk.java.net/projects/zgc/

Na https://wiki.openjdk.java.net/display/shenandoah/Main jest taki listing:

GC(3) Pause Init Mark 0.771ms
GC(3) Concurrent marking 76480M->77212M(102400M) 633.213ms
GC(3) Pause Final Mark 1.821ms
GC(3) Concurrent cleanup 77224M->66592M(102400M) 3.112ms
GC(3) Concurrent evacuation 66592M->75640M(102400M) 405.312ms
GC(3) Pause Init Update Refs 0.084ms
GC(3) Concurrent update references  75700M->76424M(102400M) 354.341ms
GC(3) Pause Final Update Refs 0.409ms
GC(3) Concurrent cleanup 76244M->56620M(102400M) 12.242ms

Fazy oznaczone jako Pause XXX wymagają zatrzymania aplikacji, ale są o rzędy wielkości krótsze niż fazy oznaczone jako Concurrent XXX, które mogą działać przy działających wątkach użytkownika.

Współbieżne działanie aplikacji i tracing GC wymaga wielu sztuczek, w zależności od tego co chcemy osiągnąć. Patrząc na wiki Shenandoah jest takie stwierdzenie:

CMS and G1 both perform concurrent marking of live objects. Shenandoah adds concurrent compaction, which means its pause times are no longer proportional to the size of the heap.

Wychodzi na to, że typowe GC już teraz działają po części współbieżnie z aplikacją, ale najbardziej problematyczna faza (tzn najdłużej trwająca) czyli compaction (defragmentacja sterty) jest najtrudniejsza do współbieżnej implementacji.

Przykładowy wpis na blogu jednego z autorów Shenadoah GC: https://rkennke.wordpress.com/2013/10/23/shenandoah-gc-brooks-pointers/

0

@Wibowit: Wiesz może, czy w dotnecie (tak, wiem, że nim gardzisz ;)) są jakieś podobne GC do Shenandonah czy ZGC albo chociaż trwają jakieś prace?

0

Nie orientuję się, ale na szybko znalazłem coś takiego: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/latency

Niestety ale tryb SustainedLowLatency pomija defragmentację sterty, a fragmentacja powoduje, że czasami nowe obiekty nie zmieszczą się w dziurach po starych i ogólne zapotrzebowanie na pamięć wzrośnie.

This mode results in a larger managed heap size than other modes. Because it does not compact the managed heap, higher fragmentation is possible. Ensure that sufficient memory is available.

Jest jeszcze jedna sprawa. Z cytatu:

ensure that the application does not access the managed heap during the collection process

nasuwa się wniosek, że może chodzić o wątki natywne dobierające się do stery zarządzanej. Nie wiem jak jest w .NETu, ale w Javce jest specjalne API (np JNI), które pozwala z poziomu kodu natywnego na dobranie się do adresu obiektu Javowego. By takie coś miało sens najpierw obiekt musi być oznaczony jako nie do ruszenia przez GC, bo jakakolwiek próba przeniesienia tego obiektu spowoduje, że wskaźnik w kodzie natywnym będzie wskazywał na niewłaściwe miejsce. Sam GC chyba też wchodzi w jakiś specjalny wolniejszy tryb, gdy obiekty Javowe są udostępniane przez JNI (czytałem o tym bardzo dawno temu i już nie jestem pewien).

1 użytkowników online, w tym zalogowanych: 0, gości: 1