Wybieranie elementów bezużytecznych Java G1 w środowisku produkcyjnym

91

Ponieważ Java 7 będzie domyślnie używać nowej funkcji czyszczenia pamięci G1, to czy Java będzie w stanie obsłużyć o rząd wielkości większą stertę bez rzekomych „niszczycielskich” czasów wstrzymania GC? Czy ktoś faktycznie wdrożył G1 do produkcji, jakie masz doświadczenia?

Szczerze mówiąc, jedyny raz, kiedy widziałem naprawdę długie przerwy w GC, dotyczyły bardzo dużych stosów, znacznie więcej niż miałaby to stacja robocza. Aby wyjaśnić moje pytanie; czy G1 otworzy bramę na sterty w setkach GB? TB?

benstpierre
źródło
16
Chociaż można to sformułować bardziej szczegółowo, nie jest to straszne pytanie. Naprawdę chciałbym, żeby ludzie podczas głosowania za zamknięciem musieli tłumaczyć się lepiej niż „To nie jest pytanie”.
Bill K
Nie głosowałem za zamknięciem, ale żałowałem, że OP nie wykonał bardziej obiektywnej pracy, szczegółowo opisując swoje zastrzeżenia w obecnym GC. Poza tym „Java” jest językiem, podczas gdy on mówi o implementacji, a ja nie wiem, co oznacza „wdrożenie G1 w środowisku produkcyjnym”, szczególnie w przypadku czasu przyszłego pozostałej części pytania. Jeśli ma być w Javie 7, na pewno nikt nie użył go w produkcji?
Pascal Cuoq,
6
@Pascal G1 był eksperymentalną funkcją dostępną w JDK od aktualizacji 14 JDK 6. Myślę, że przez „wdrożenie G1 do produkcji” miał na myśli faktyczne użycie, nie jest to trudne do oszacowania. I chociaż zgadzam się, że G1 jest częścią JDK 7, a nie Java, wyszukiwanie Java 7 w Google zwraca stronę główną JDK 7 jako pierwszy wynik, a oba terminy są często używane zamiennie. @Benju Nie ufałbym wynikom uzyskanym z G1 na obecnym JDK, ponieważ jest eksperymentalny, wiele rzeczy może się zmienić od teraz do oficjalnej wersji.
teto
2
Wygląda na to, że JDK 7, w tym aktualizacja 1, 2 i 3, nie używa domyślnie G1 gc. Możesz to sprawdzić przez jinfo -flag UseG1GC pid
George

Odpowiedzi:

34

Wygląda na to, że celem G1 jest krótsze czasy pauzy, nawet do punktu, w którym ma możliwość określenia maksymalnego docelowego czasu pauzy.

Zbieranie śmieci nie jest już tylko prostym rozwiązaniem typu „Hej, jest pełne, przenieśmy wszystko na raz i zacznijmy od nowa” - to fantastycznie złożony, wielopoziomowy, wątkowy system działający w tle. Może wykonywać wiele czynności konserwacyjnych w tle bez żadnych przerw, a także wykorzystuje wiedzę o oczekiwanych wzorcach systemu w czasie wykonywania, aby pomóc - na przykład zakładając, że większość obiektów umiera zaraz po utworzeniu itp.

Powiedziałbym, że czasy wstrzymania GC będą nadal się poprawiać, a nie pogarszać, w przyszłych wydaniach.

EDYTOWAĆ:

Po ponownym przeczytaniu dotarło do mnie, że codziennie używam Javy - Eclipse, Azureus i aplikacji, które tworzę, i minęło DŁUGO CZAS, odkąd zobaczyłem przerwę. Nie znacząca pauza, ale mam na myśli jakąkolwiek pauzę.

Widziałem przerwy, kiedy klikam prawym przyciskiem myszy w Eksploratorze Windows lub (czasami), kiedy podłączam określony sprzęt USB, ale z Javą - w ogóle.

Czy GC nadal jest problemem dla kogoś?

Bill K.
źródło
Zgadzam się - jedyny raz, kiedy widziałem pauzy w GC, to kiedy celowo lub przypadkowo sprowokowałem je masowo równoległym kodem tworzącym śmieci .....
mikera
28
Tak, GC nadal stanowi poważny problem, gdy zaczynasz zajmować się dużymi stosami (> 16 GB), szczególnie w przypadku dużych pokoleń najemnych.
The Alchemist
2
@ the-alchemist wow, kilka razy widziałem twój komentarz i właśnie dotarło do mnie, że powiedziałeś 16 GB !! Chociaż jestem absolutnie pewien, że masz rację, że może to powodować ogromne opóźnienia, chcę sprawdzić, czy wyłączyłeś WSZYSTKIE zamiany. W przypadku dużego systemu pamięci każda zamiana java całkowicie zabije twój system (ponieważ GC jest bardzo nieprzyjazny dla zamiany). Jestem pewien, że już to zrobiłeś, ale chciałem tylko o tym wspomnieć - ponieważ miałoby to ogromne znaczenie. Nigdy nie widziałem komputera z tak dużą ilością pamięci RAM - ile masz? 32g?
Bill K
8
Tak, GC są problematyczne dla usług, ponieważ to właśnie one BARDZO utrudniają poprawę limitów TP99.9 (i wyższych). W szczególności GC „starej generacji” mogą być śmiertelnymi pułapkami, które zamrażają JVM (i serwis) na wiele sekund; aw przypadku usług, które zazwyczaj obsługują żądania w jednocyfrowych (lub małych dwucyfrowych) milisekundach, jest to problematyczne. Na ile to warte, był to praktyczny problem z pamięcią masową zaplecza używaną przez usługę Simple Queue firmy Amazon (nie można wchodzić w mnóstwo szczegółów, ponieważ jest to AWS).
StaxMan
21
Irytujące w GC jest to, że Azul wymyślił wiele lat temu genialny algorytm GC (Azul C4), który może z łatwością radzić sobie z setkami gigabajtów bez zauważalnych przerw, bardzo sprytnie wykorzystując sprzęt pamięci procesora. Ale nikt o tym nie wie i nie zostanie on wkrótce zaimplementowany w głównych wersjach Javy, ponieważ wymaga wsparcia ze strony systemu operacyjnego. A producenci systemów operacyjnych nie zrobią nic, dopóki ludzie nie dowiedzą się o algorytmie i nie wywierają presji na dostawców systemów operacyjnych. Zobacz azulsystems.com/zing/pgc , managedruntime.org
Hans-Peter Störr
58

Testowałem to z ciężką aplikacją: 60-70 GB przydzielone do sterty, a 20-50 GB w użyciu w dowolnym momencie. W przypadku tego rodzaju zastosowań stwierdzenie, że przebieg może się różnić, jest niedopowiedzeniem. Używam JDK 1.6_22 w systemie Linux. Wersje podrzędne są ważne - przed około 1.6_20 w G1 były błędy, które powodowały losowe wyjątki NullPointerExceptions.

Odkryłem, że bardzo dobrze trzyma się celu pauzy, który dajesz mu przez większość czasu. Wydaje się, że domyślną przerwą jest 100 ms (0,1 sekundy), a ja mówiłem mu, aby zrobił połowę tego (-XX: MaxGCPauseMillis = 50). Jednak gdy zaczyna brakować pamięci, panikuje i całkowicie usuwa śmieci ze świata. Przy 65 GB zajmuje to od 30 sekund do 2 minut. (Liczba procesorów prawdopodobnie nie robi różnicy; prawdopodobnie jest ograniczona przez prędkość magistrali).

W porównaniu z CMS (który nie jest domyślnym GC serwera, ale powinien być dla serwerów WWW i innych aplikacji czasu rzeczywistego), typowe przerwy są znacznie bardziej przewidywalne i można je znacznie skrócić. Jak dotąd mam więcej szczęścia z CMS w przypadku dużych przerw, ale to może być przypadkowe; Widzę je tylko kilka razy w ciągu 24 godzin. Nie jestem pewien, który w tej chwili będzie bardziej odpowiedni w moim środowisku produkcyjnym, ale prawdopodobnie G1. Jeśli Oracle będzie dalej go dostrajać, podejrzewam, że ostatecznie zdecydowanym zwycięzcą będzie G1.

Jeśli nie masz problemu z istniejącymi odśmiecaczami, nie ma powodu, aby teraz rozważać G1. Jeśli używasz aplikacji o niskim opóźnieniu, takiej jak aplikacja GUI, G1 jest prawdopodobnie właściwym wyborem, z MaxGCPauseMillis ustawionym naprawdę nisko. Jeśli używasz aplikacji w trybie wsadowym, G1 nic ci nie kupi.

David Leppik
źródło
14

Chociaż nie testowałem G1 w produkcji, pomyślałem, że skomentuję, że GC są już problematyczne dla przypadków bez „ogromnych” stosów. GC może mieć poważny wpływ na usługi z, powiedzmy, 2 lub 4 koncertami. GC młodego pokolenia zwykle nie stanowią problemu, ponieważ kończą się w jednocyfrowych milisekundach (lub co najwyżej dwucyfrowych). Ale kolekcje starej generacji są znacznie bardziej problematyczne, ponieważ zajmują wiele sekund przy rozmiarach starej generacji wynoszących 1 gig lub więcej.

Otóż: teoretycznie CMS może tam bardzo pomóc, ponieważ większość operacji może działać równolegle. Jednak z biegiem czasu zdarzają się sytuacje, w których nie może tego zrobić i będzie musiał wrócić do zbiórki „stop the world”. A kiedy to się stanie (powiedzmy po 1 godzinie - niezbyt często, ale wciąż za często), no cóż, trzymaj się swoich pieprzonych czapek. Może to zająć minutę lub dłużej. Jest to szczególnie problematyczne w przypadku usług, które próbują ograniczyć maksymalne opóźnienia; zamiast, powiedzmy, 25 milisekund, aby obsłużyć żądanie, zajmuje teraz dziesięć sekund lub dłużej. Aby dodać obrażenia do obrażeń, klienci często przekraczają limit czasu i ponawiają żądanie, co prowadzi do dalszych problemów (tzw. „Burza gówna”).

Jest to jeden obszar, w którym G1 miał nadzieję bardzo pomóc. Pracowałem dla dużej firmy, która oferuje usługi w chmurze do przechowywania i wysyłania wiadomości; i nie mogliśmy użyć CMS, ponieważ chociaż przez większość czasu działał lepiej niż równoległe odmiany, miał te załamania. Tak więc przez około godzinę było fajnie; a potem coś uderzyło w wentylator ... a ponieważ usługa była oparta na klastrach, kiedy jeden węzeł miał kłopoty, inne zazwyczaj podążały za nimi (ponieważ przekroczenia czasu spowodowane przez GC prowadzą do tego, że inne węzły uważają, że węzeł uległ awarii, co prowadzi do ponownych tras).

Nie sądzę, aby GC stanowiło tak duży problem dla aplikacji, a być może nawet usługi nieklastrowe są rzadziej dotykane. Jednak coraz więcej systemów jest klastrowanych (szczególnie dzięki magazynom danych NoSQL), a rozmiary stert rosną. GC OldGen są superliniowo powiązane z rozmiarem sterty (co oznacza, że ​​podwojenie rozmiaru sterty ponad dwukrotnie zwiększa czas GC, zakładając, że rozmiar zestawu danych na żywo również się podwoi).

StaxMan
źródło
13

CTO firmy Azul, Gil Tene, ma ładny przegląd problemów związanych z Garbage Collection i przegląd różnych rozwiązań w swojej prezentacji Understanding Java Garbage Collection and What You Can Do About It , a dodatkowe szczegóły znajdują się w tym artykule: http: // www.infoq.com/articles/azul_gc_in_detail .

C4 Garbage Collector firmy Azul w naszej JVM Zing jest zarówno równoległe, jak i współbieżne i używa tego samego mechanizmu GC zarówno dla nowej, jak i starej generacji, działając jednocześnie i kompaktując w obu przypadkach. Co najważniejsze, C4 nie ma możliwości cofnięcia się świata. Całe kompaktowanie jest wykonywane jednocześnie z uruchomioną aplikacją. Mamy klientów korzystających z bardzo dużych (setki GB) z czasem przerwy GC w gorszym przypadku <10 ms, aw zależności od aplikacji często krótszym niż 1-2 ms.

Problem z CMS i G1 polega na tym, że w pewnym momencie pamięć sterty Java musi zostać skompaktowana, a oba te moduły odśmiecania pamięci zatrzymują świat / STW (tj. Wstrzymują aplikację), aby wykonać kompaktowanie. Więc chociaż CMS i G1 mogą wypychać przerwy w STW, nie eliminują ich. Jednak C4 Azul całkowicie eliminuje przerwy w STW i dlatego Zing ma tak niskie przerwy w GC nawet dla gigantycznych rozmiarów sterty.

Aby poprawić stwierdzenie zawarte we wcześniejszej odpowiedzi, Zing nie wymaga żadnych zmian w systemie operacyjnym. Działa jak każda inna maszyna JVM na niezmodyfikowanych dystrybucjach Linuksa.

Scott Sellers
źródło
3
Zastanawiam się tylko, jak C4 firmy Azul osiągnęło to, co powiedziałeś, i dlaczego Sun lub Oracle nie mogą. Czy jest jakaś wielka tajemnica, czy to po prostu jakiś kompromis?
George
5
C4 firmy Azul ma bardzo unikalną technologię, która ma swoje korzenie w sprzętowych urządzeniach obliczeniowych firmy Azul (które wykorzystują wyspecjalizowane procesory zbudowane do uruchamiania korporacyjnych aplikacji Java) i ewoluowała do działania na zwykłych serwerach x86 z systemem Linux. Każdy inny zbieracz śmieci klasy korporacyjnej (czy to z Oracle, czy IBM) w pewnym momencie musi robić przerwy w zatrzymywaniu świata - unikalnym atrybutem C4 firmy Azul jest to, że nigdy nie robi tych problematycznych przerw w STW. Jeśli jesteś ciekawy, wynalazcy kolektora C4 opublikowali artykuł o tym, jak to działa: dl.acm.org/citation.cfm?id=1064988 .
Scott Sellers
Scott, przeczytałem tutaj blog.mikemccandless.com/2012/07/, że Azul dostarcza moduł jądra, który wstępnie alokuje pamięć do użycia JVM. Czy to nieprawda? Jeśli prawda, to niewiele modyfikacji jądra, ale nadal modyfikacja.
Dan Pritts,
4
George, dwa słowa: chroniony patentem. Dan, kupując Zinga, część tego, za co płacisz, polega na tym, że pracownicy pomocy technicznej dostroili go do Twojej aplikacji - i obejmuje to przydzielenie całkowitego zużycia pamięci systemowej. Sam moduł jądra zapobiega zapisom do bloku pamięci, który jest usuwany jako śmieci. To jest sekretny sos, który sprawia, że ​​jest „bez przerw”: wątki zatrzymują się tylko wtedy, gdy próbują pisać do jednego z tych bloków, a potem tylko na tyle długo, aby go zagęścić.
David Leppik,
13

Używamy G1GC już od prawie dwóch lat. Świetnie radzi sobie w naszym systemie przetwarzania transakcji o znaczeniu krytycznym i okazał się świetnym wsparciem przy dużej przepustowości, małych przerwach, współbieżności i zoptymalizowanym zarządzaniu dużą ilością pamięci.

Używamy następujących ustawień JVM:

-server -Xms512m -Xmx3076m -XX:NewRatio=50 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000 -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime

Zaktualizowano

-d64 -server -Xss4m -Xms1024m -Xmx4096m -XX:NewRatio=50 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:-DisableExplicitGC -XX:+AggressiveOpts -Xnoclassgc -XX:+UseNUMA -XX:+UseFastAccessorMethods -XX:ReservedCodeCacheSize=48m -XX:+UseStringCache -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000
emkays
źródło
5
W Javie 8 nie ma potrzeby ustawiania -XX: + UseCompressedOops lub -XX: + DoEscapeAnalysis, budki są domyślnie włączone. Zobacz: docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
Mirko Ebert
8

Kolektor G1 zmniejsza wpływ pełnych kolekcji. Jeśli masz aplikację, w której już zmniejszyłeś zapotrzebowanie na pełne kolekcje, kolekcjoner map Concurrent Sweep jest równie dobry iz moim doświadczeniem ma krótsze mniejsze czasy odbioru.

Peter Lawrey
źródło
„zwróć uwagę, że produkcyjne użycie G1 jest dozwolone tylko w przypadku zakupu umowy wsparcia Java.”, groups.google.com/forum/#!topic/javaposse/Vm0a4H-QY54 , więc jest to mit czy nie?
Christophe Roussy
1
@ChristopheRoussy Nie wiem, czy to już prawda (lub rzeczywiście mam dowód, że kiedykolwiek była prawdą). Nie wymaga to -XX: + UnlockCommercialFeatures, więc podejrzewam, że G1 nie wymaga licencji.
Peter Lawrey,
5

Ostatnio przeniosłem się z

CMS do G1GC ze stertą 4G i 8-rdzeniowym procesorem na serwerach z JDK 1.7.45 .

(JDK 1.8.x G1GC jest preferowany od 1.7, ale z powodu pewnych ograniczeń muszę trzymać się wersji 1.7.45)

Skonfigurowałem poniżej kluczowe parametry i zachowałem wszystkie inne parametry do wartości domyślnych.

-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n apart from -Xms and -Xmx

Jeśli chcesz dostroić te parametry, zapoznaj się z tym artykułem w wyroczni .

Kluczowe obserwacje:

  1. Wykorzystanie pamięci jest zgodne z G1GC, w przeciwieństwie do wysokich i niskich wartości z CMS
  2. Maksymalny czas przerwy w GC jest krótszy w porównaniu do CMS
  3. Czas spędzony na zbieraniu śmieci jest trochę za długi w G1GC w porównaniu z CMS.
  4. Liczba dużych kolekcji jest prawie znikoma w porównaniu z CMS
  5. Liczba pomniejszych kolekcji jest na wyższym końcu w porównaniu do CMS

Ale nadal cieszę się, że czas pauzy Max GC jest krótszy niż w CMS. Ustawiłem czas pauzy Max GC na 1,5 sekundy i ta wartość nie została jeszcze przekroczona.

Powiązane pytanie SE:

Wyrzucanie elementów bezużytecznych w Javie 7 (JDK 7) i dokumentacja na G1

Ravindra babu
źródło
4

CMS może prowadzić do powolnego obniżania wydajności, nawet jeśli jest uruchamiany bez gromadzenia nabytych obiektów. Dzieje się tak z powodu fragmentacji pamięci, której G1 rzekomo unika.

Mit o G1 dostępnym tylko z płatnym wsparciem jest po prostu mitem. Sun, a teraz Oracle wyjaśnili to na stronie JDK.

Ted Dunning
źródło
4

G1 GC ma działać lepiej. Ale jeśli ustawienie -XX: MaxGCPauseMill jest zbyt agresywne, śmieci będą zbierane zbyt wolno. I dlatego w przykładzie Davida Leppika uruchomiono pełne GC.

hypheng
źródło
4

Właśnie zaimplementowałem G1 Garbage Collector w naszym projekcie Terracotta Big Memory. Podczas pracy z różnymi typami kolektorów G1 dał nam najlepsze wyniki przy czasie odpowiedzi poniżej 600ms.

Wyniki testu (łącznie 26) można znaleźć tutaj

Mam nadzieję, że to pomoże.

Hiszpański
źródło
3

Niedawno przeprowadziłem migrację części Twicsy na nowy serwer ze 128 GB pamięci RAM i zdecydowałem się użyć wersji 1.7. Zacząłem od tych samych ustawień pamięci, co w 1.6 (mam kilka instancji wykonujących różne rzeczy, od 500 MB do 15 GB, a teraz nowy z 40 GB) i to wcale nie wyszło dobrze . Wydaje się, że 1.7 używa więcej sterty niż 1.6 i przez kilka pierwszych dni miałem wiele problemów. Na szczęście miałem dużo pamięci RAM do pracy i zwiększyłem pamięć RAM dla większości moich procesów, ale nadal miałem pewne problemy. Moje normalne MO polegało na użyciu bardzo małego minimalnego rozmiaru sterty 16 m, nawet przy maksymalnej sterty kilku gigabajtów, a następnie włączenie przyrostowego GC. To ograniczyło przerwy do minimum. To jednak teraz nie działa i musiałem zwiększyć minimalny rozmiar do mniej więcej tego, czego spodziewałem się średnio na stercie, i to bardzo dobrze się udało. Nadal mam włączone przyrostowe GC, ale spróbuję bez. Żadnych przerw w tej chwili i wydaje się, że wszystko przebiega bardzo szybko. Myślę więc, że morał tej historii polega na tym, że nie oczekuj, że ustawienia pamięci będą się doskonale przekładać z 1,6 na 1,7.

Chris Seline
źródło
2

G1 sprawia, że ​​aplikacja jest dużo bardziej zwinna: opóźnienie aplikacji wzrośnie - aplikację można nazwać „miękkim czasie rzeczywistym”. Odbywa się to poprzez zastąpienie dwóch rodzajów przebiegów GC (małych mniejszych i jednego dużego w Tenured Gen) na równej wielkości małe.

Aby uzyskać więcej informacji, spójrz na to: http://geekroom.de/java/java-expertise-g1-fur-java-7/

Daniel
źródło
1

Pracuję z Javą, dla małego i dużego Heap, a pytanie o GC i Full GC pojawia się każdego dnia, ponieważ ograniczenia mogą być bardziej rygorystyczne niż inne: w pewnym środowisku 0,1 sekundy scavenger GC lub Full GC, kill po prostu fonctionnalité, a drobnoziarnista konfiguracja i możliwości są ważne (CMS, iCMS, inne ... celem jest tutaj uzyskanie najlepszego możliwego czasu odpowiedzi z leczeniem w czasie prawie rzeczywistym (tutaj leczenie w czasie rzeczywistym często wynosi 25 ms) , więc w zasadzie wszelkie ulepszenia w ergonomii i heurystyce GC są mile widziane!

Fuby
źródło
1

Używam G1GC na Javie 8, a także z Groovy (także Java 8) i wykonuję różne rodzaje obciążeń, a ogólnie G1GC działa tak:

  • Zużycie pamięci jest bardzo niskie, np. 100 MB zamiast 500 MB w porównaniu z domyślnymi ustawieniami Java

  • Czas odpowiedzi jest stały i bardzo krótki

  • Wydajność między ustawieniami domyślnymi a G1GC to 20% spowolnienie podczas korzystania z G1GC w najgorszym przypadku (bez strojenia, aplikacja jednowątkowa). To niewiele, biorąc pod uwagę dobry czas odpowiedzi i niskie zużycie pamięci.

  • W przypadku korzystania z wielowątkowego serwera Tomcat ogólna wydajność jest o 30% lepsza, a zużycie pamięci jest znacznie niższe, a czasy odpowiedzi są znacznie niższe.

Ogólnie rzecz biorąc, podczas korzystania z naprawdę różnych obciążeń G1GC jest bardzo dobrym kolektorem Java 8 dla aplikacji wielowątkowych, a nawet w przypadku jednowątków ma pewne zalety.

Andrzej
źródło
0

Nie zaleca się używania java8 w / G1GC do obliczania punktu zmiennoprzecinkowego z JVM podobnym do hotspotu. Jest to niebezpieczne dla integralności i dokładności aplikacji.

https://bugs.openjdk.java.net/browse/JDK-8148175

JDK-8165766

JDK-8186112

user7796409
źródło