Udostępnij przez


Powody przejścia do środowiska Java 11 i nowszych

Nie chodzi o to , czy należy przejść do środowiska Java 11 lub nowszej wersji, ale kiedy. W ciągu najbliższych kilku lat środowisko Java 8 nie będzie już obsługiwane, a użytkownicy będą musieli przejść do środowiska Java 11 lub nowszego. Twierdzimy, że istnieją korzyści wynikające z przejścia do środowiska Java 11 i zachęcamy zespoły do tego tak szybko, jak to możliwe.

Od wersji Java 8 dodano nowe funkcje i wprowadzono ulepszenia. Istnieją zauważalne dodatki i modyfikacje interfejsu API, a także wprowadzono ulepszenia zwiększające uruchamianie, wydajność i użycie pamięci.

Przechodzenie do środowiska Java 11

Przejście do środowiska Java 11 można wykonać krokowo. Nie jest wymagane , aby kod używał modułów Java do uruchamiania w środowisku Java 11. Język Java 11 może służyć do uruchamiania kodu opracowanego i skompilowanego za pomocą zestawu JDK 8. Istnieją jednak pewne potencjalne problemy, przede wszystkim dotyczące przestarzałego interfejsu API, ładowania klas i refleksji.

Grupa inżynierów Języka Java firmy Microsoft ma przewodnik po przejściu z języka Java 8 do języka Java 11. Przewodnik Java Platform, Standard Edition Oracle JDK 9 Migration Guide i The State of the Module System: Compatibility and Migration są innymi przydatnymi przewodnikami.

Zmiany wysokiego poziomu między językiem Java 8 i 11

Ta sekcja nie wylicza wszystkich zmian wprowadzonych w języku Java w wersjach 9 [1], 10 [2] i 11 [3]. Wyróżniono zmiany, które mają wpływ na wydajność, diagnostykę i produktywność.

Moduły [4]

Moduły umożliwiają rozwiązywanie problemów z konfiguracją i hermetyzacją, które są trudne do zarządzania w aplikacjach na dużą skalę uruchomionych na ścieżce klasy. Moduł to samoopisujący się zbiór klas i interfejsów Języka Java oraz powiązanych zasobów.

Moduły umożliwiają dostosowanie konfiguracji środowiska uruchomieniowego, które zawierają tylko składniki wymagane przez aplikację. To dostosowanie zmniejsza zasobożerność i umożliwia statyczne łączenie aplikacji przy użyciu jlink do niestandardowego środowiska uruchomieniowego na potrzeby wdrożenia. Ten mniejszy ślad może być szczególnie przydatny w architekturze mikrousług.

Wewnętrznie maszyny JVM mogą korzystać z modułów w sposób, który sprawia, że ładowanie klas jest bardziej wydajne. Wynikiem jest środowisko uruchomieniowe, które jest mniejsze, lżejsze i szybsze do uruchomienia. Techniki optymalizacji używane przez maszynę JVM w celu zwiększenia wydajności aplikacji mogą być bardziej skuteczne, ponieważ moduły kodują składniki wymagane przez klasę.

W przypadku programistów moduły pomagają wymusić silną hermetyzację, wymagając jawnej deklaracji, które pakiety moduł eksportuje i jakich składników wymaga, oraz ograniczając dostęp refleksyjny. Ten poziom hermetyzacji sprawia, że aplikacja jest bezpieczniejsza i łatwiejsza w obsłudze.

Aplikacja może nadal używać ścieżki klasy i nie musi przechodzić do modułów jako wymagań dotyczących uruchamiania w środowisku Java 11.

Profilowanie i diagnostyka

Java Flight Recorder [5]

Narzędzie Java Flight Recorder (JFR) zbiera dane diagnostyczne i profilowanie z uruchomionej aplikacji Java. JFR ma niewielki wpływ na działającą aplikację Java. Zebrane dane można następnie analizować za pomocą narzędzia Java Mission Control (JMC) i innych narzędzi. Mając na uwadze, że JFR i JMC były funkcjami komercyjnymi w środowisku Java 8, oba są typu open source w środowisku Java 11.

Java Mission Control [6]

Narzędzie Java Mission Control (JMC) udostępnia graficzne wyświetlanie danych zebranych przez narzędzie Java Flight Recorder (JFR) i jest oprogramowaniem open source w środowisku Java 11. Oprócz ogólnych informacji o uruchomionej aplikacji usługa JMC umożliwia użytkownikowi przechodzenie do szczegółów danych. JFR i JMC mogą służyć do diagnozowania problemów ze środowiskiem uruchomieniowym, takich jak przecieki pamięci, obciążenie pamięci, metody gorące, wąskie gardła wątków i blokowanie operacji we/wy.

Ujednolicone rejestrowanie [7]

Środowisko Java 11 ma wspólny system rejestrowania dla wszystkich składników maszyny wirtualnej JVM. Ten ujednolicony system rejestrowania umożliwia użytkownikowi zdefiniowanie składników do rejestrowania i na jakim poziomie. To szczegółowe rejestrowanie jest przydatne do przeprowadzania analizy głównej przyczyny awarii maszyny wirtualnej JVM i diagnozowania problemów z wydajnością w środowisku produkcyjnym.

Profilowanie stert z niskim obciążeniem [8]

Dodano nowy interfejs API w Java Virtual Machine Tool Interface (JVMTI) do próbkowania alokacji sterty Java. Próbkowanie ma niskie obciążenie systemowe i można je włączać ciągle. Chociaż alokacja sterty może być monitorowana za pomocą narzędzia Java Flight Recorder (JFR), metoda próbkowania w programie JFR działa tylko na alokacjach. Implementacja JFR może również przegapić alokacje. Natomiast próbkowanie stert w środowisku Java 11 może dostarczać informacje o obiektach na żywo i martwym.

Dostawcy programu Application Performance Monitoring (APM) zaczynają korzystać z tej nowej funkcji, a grupa inżynierów Języka Java bada potencjalne użycie z narzędziami do monitorowania wydajności platformy Azure.

StackWalker [9]

Pobieranie migawki stosu dla bieżącego wątku często jest używane podczas rejestrowania. Problem polega na tym, ile śladu stosu ma być rejestrowane i czy w ogóle taki ślad rejestrować. Na przykład można zobaczyć ślad stosu tylko dla określonego wyjątku z metody. Klasa StackWalker (wprowadzona w Java 9) tworzy migawkę stosu i oferuje metody, które dają programiście możliwość precyzyjnego zarządzania sposobem korzystania z informacji o śledzeniu stosu.

Kolekcja śmieci [10]

Następujące kolektory odpadów są dostępne w Java 11: Serial, Parallel, Garbage-First i Epsilon. Domyślny kolektor śmieci w Java 11 to Garbage First Garbage Collector (G1GC).

Wymieniono tutaj trzy inne kolektory dla pełności informacji. Kolektor odśmiecania pamięci Z (ZGC) to współbieżny kolektor o małych opóźnieniach, który stara się utrzymać czas wstrzymania poniżej 10 ms. ZGC jest dostępna jako funkcja eksperymentalna w środowisku Java 11. Shenandoah to kolektor o niskich wstrzymaniach, który skraca czasy wstrzymań GC, wykonując więcej operacji zbierania śmieci współbieżnie z działającym programem Java. Shenandoah to funkcja eksperymentalna w środowisku Java 12, ale istnieją backporty do środowiska Java 11. Kolektor Concurrent Mark and Sweep (CMS) jest dostępny, ale został wycofany od wersji Java 9.

Maszyny JVM ustawiają wartości domyślne GC dla średniego przypadku użycia. Często te ustawienia domyślne i inne ustawienia GC muszą być dostrojone w celu uzyskania optymalnej przepływności lub opóźnienia zgodnie z wymaganiami aplikacji. Prawidłowe dostrajanie GC wymaga dogłębnej wiedzy na temat GC, wiedzy, którą zapewnia grupa inżynierów Języka Java firmy Microsoft .

G1GC

Domyślny kolektor śmieci w Java 11 to kolektor G1 (G1GC). Celem G1GC jest zrównoważenie opóźnienia i przepływności. Kolektor odpadów G1 próbuje osiągnąć wysoką wydajność, osiągając utrzymanie celów dotyczących czasu pauzy z wysokim prawdopodobieństwem. G1GC został zaprojektowany tak, aby unikać pełnych kolekcji, ale gdy współbieżne kolekcje nie mogą odzyskać pamięci wystarczająco szybko, nastąpi pełny GC w ramach rezerwy. Pełna GC używa tej samej liczby równoległych wątków procesów roboczych co młode i mieszane kolekcje.

Równoległa GC

Moduł zbierający równoległy jest domyślnym modułem zbierającym w języku Java 8. Parallel GC to moduł zbierający przepływność, który używa wielu wątków do przyspieszenia odzyskiwania pamięci.

Epsilon [11]

Moduł zbierający śmieci Epsilon obsługuje alokacje, ale nie odzyskuje żadnej pamięci. Po wyczerpaniu sterty JVM, maszyna zostanie zamknięta. Epsilon jest przydatny w przypadku krótkoterminowych usług i aplikacji, które są znane jako wolne od odpadków.

Ulepszenia kontenerów platformy Docker [12]

Przed użyciem środowiska Java 10 ograniczenia pamięci i procesora CPU ustawione dla kontenera nie zostały rozpoznane przez maszynę wirtualną JVM. Na przykład w języku Java 8 maszyna wirtualna JVM domyślnie ustawi maksymalny rozmiar sterty na 1/4 pamięci fizycznej bazowego hosta. Począwszy od środowiska Java 10, maszyny JVM używają ograniczeń ustawionych przez grupy kontrolek kontenerów (cgroups) w celu ustawienia limitów pamięci i procesora CPU (patrz uwaga poniżej). Na przykład domyślny maksymalny rozmiar sterty to 1/4 limitu pamięci kontenera (np. 500 MB dla -m2G).

Dodano również opcje JVM w celu zapewnienia użytkownikom kontenera platformy Docker precyzyjnej kontroli nad ilością pamięci systemowej, która będzie używana na stercie Java.

Ta obsługa jest domyślnie włączona i jest dostępna tylko na platformach opartych na systemie Linux.

Uwaga / Notatka

Większość prac związanych z włączaniem cgroup została przeniesiona wstecz do środowiska Java 8, począwszy od wersji jdk8u191. Dalsze ulepszenia mogą niekoniecznie zostać przywrócone do wersji 8.

Pliki jar obsługujące wiele wersji [13]

W języku Java 11 można utworzyć plik jar zawierający wiele wersji specyficznych dla języka Java plików klas. Pliki jar z wieloma wersjami umożliwiają deweloperom bibliotek obsługę wielu wersji języka Java bez konieczności dostarczania wielu wersji plików jar. Dla użytkowników tych bibliotek, wielowersyjne pliki jar rozwiązują problem konieczności dopasowywania określonych plików jar do określonych celów środowiska uruchomieniowego.

Różne ulepszenia wydajności

Następujące zmiany w maszynie JVM mają bezpośredni wpływ na wydajność.

  • JEP 197: Segmented Code Cache [14] — dzieli pamięć podręczną kodu na odrębne segmenty. Ta segmentacja zapewnia lepszą kontrolę nad zużyciem pamięci JVM, skraca czas skanowania skompilowanych metod, znacznie zmniejsza fragmentację pamięci podręcznej kodu i poprawia wydajność.

  • JEP 254: Kompaktowe ciągi [15] — zmienia wewnętrzną reprezentację ciągu z dwóch bajtów na znak do jednego lub dwóch bajtów na znak, w zależności od kodowania znaków. Ponieważ większość ciągów zawiera znaki ISO-8859-1/Latin-1, ta zmiana skutecznie zmniejsza ilość miejsca wymaganego do przechowywania ciągu.

  • JEP 310: Udostępnianie aplikacji Class-Data [16] — udostępnianie Class-Data zmniejsza czas uruchamiania, umożliwiając zamapowanie zarchiwizowanych klas w czasie wykonywania. Udostępnianie klas danych aplikacji rozszerza udostępnianie danych klas, umożliwiając umieszczanie klas aplikacji w archiwum CDS. Gdy wiele maszyn wirtualnych JVM współdzieli ten sam plik archiwum, oszczędzana jest pamięć, a ogólny czas reakcji systemu ulega poprawie.

  • JEP 312: Lokalne Uzgadnianie Wątków [17] — umożliwia wykonywanie wywołań zwrotnych w wątkach bez wykonywania globalnego punktu zatrzymania maszyny wirtualnej, co pomaga maszynie wirtualnej uzyskać mniejszą latencję dzięki zmniejszeniu liczby globalnych punktów zatrzymania.

  • Leniwa alokacja wątków kompilatora [18] — w trybie kompilacji warstwowej maszyna wirtualna uruchamia dużą liczbę wątków kompilatora. Ten tryb jest domyślny w systemach z wieloma procesorami CPU. Te wątki są tworzone niezależnie od dostępnej pamięci lub liczby żądań kompilacji. Wątki zużywają pamięć nawet wtedy, gdy są bezczynne (czyli przez niemal cały czas), co prowadzi do nieefektywnego wykorzystania zasobów. Aby rozwiązać ten problem, implementacja została zmieniona, aby uruchomić tylko jeden wątek kompilatora każdego typu podczas uruchamiania. Uruchamianie dodatkowych wątków i zamykanie nieużywanych wątków jest obsługiwane dynamicznie.

Następujące zmiany w bibliotekach podstawowych mają wpływ na wydajność nowego lub zmodyfikowanego kodu.

  • JEP 193: Dojścia zmiennych [19] — definiuje standardowe metody wywoływania odpowiedników różnych operacji java.util.concurrent.atomic i sun.misc.Unsafe na polach obiektów i elementach tablicy, standardowego zestawu operacji ogrodzenia w celu precyzyjnej kontroli kolejności pamięci oraz standardowej operacji ogrodzenia osiągalności w celu zapewnienia, że przywoływane obiekty pozostają silnie osiągalne.

  • JEP 269: Wygodne metody fabryki kolekcji [20] — definiuje interfejsy API biblioteki, aby ułatwić tworzenie wystąpień kolekcji i map z małą liczbą elementów. Statyczne metody fabryczne na interfejsach kolekcji, które tworzą kompaktowe i niemodyfikowalne wystąpienia kolekcji. Te wystąpienia są z natury bardziej wydajne. API tworzą kolekcje, które są zwarto reprezentowane i nie mają klasy opakowującej.

  • JEP 285: Spin-Wait Hints [21] — udostępnia interfejs API, który umożliwia środowisku Java przekazywać wskazówki systemowi czasu wykonywania, że znajduje się w pętli spin. Niektóre platformy sprzętowe korzystają ze wskazania oprogramowania, że wątek jest w stanie aktywnego oczekiwania.

  • JEP 321: Klient HTTP (Standardowa) [22] — udostępnia nowy interfejs API klienta HTTP, który implementuje protokoły HTTP/2 i WebSocket i może zastąpić starszy interfejs API httpURLConnection.

References

[1] Oracle Corporation, "Java Development Kit 9 Release Notes", (Online). Dostępne: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (Dostęp do 13 listopada 2019 r.).

[2] Oracle Corporation, "Java Development Kit 10 Release Notes", (Online). Dostępne: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (Dostęp do 13 listopada 2019 r.).

[3] Oracle Corporation, "Java Development Kit 11 Release Notes", (Online). Dostępne: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (Dostęp do 13 listopada 2019 r.).

[4] Oracle Corporation, "Project Jigsaw", wrzesień 22, 2017. (Online). Dostępne: http://openjdk.java.net/projects/jigsaw/. (Dostęp do 13 listopada 2019 r.).

[5] Oracle Corporation, "JEP 328: Flight Recorder", 9 września 2018. (Online). Dostępne: http://openjdk.java.net/jeps/328. (Dostęp do 13 listopada 2019 r.).

[6] Oracle Corporation, "Mission Control", kwiecień 25, 2019. (Online). Dostępne: https://wiki.openjdk.java.net/display/jmc/Main. (Dostęp do 13 listopada 2019 r.).

[7] Oracle Corporation, "JEP 158: Unified JVM Logging", 14 lutego 2019. (Online). Dostępne: http://openjdk.java.net/jeps/158. (Dostęp do 13 listopada 2019 r.).

[8] Oracle Corporation, "JEP 331: Profilowanie sterty o niskim narzucie", 5 września 2018 r. (Online). Dostępne: http://openjdk.java.net/jeps/331. (Dostęp do 13 listopada 2019 r.).

[9] Oracle Corporation, "JEP 259: Stack-Walking API", lipiec 18, 2017. (Online). Dostępne: http://openjdk.java.net/jeps/259. (Dostęp do 13 listopada 2019 r.).

[10] Oracle Corporation, "JEP 248: Make G1 the Default Garbage Collector", 12 września 2017. (Online). Dostępne: http://openjdk.java.net/jeps/248. (Dostęp uzyskano 13 listopada 2019 r.).

[11] Oracle Corporation, "JEP 318: Epsilon: A No-Op Garbage Collector", 24 września 2018. (Online). Dostępne: http://openjdk.java.net/jeps/318. (Dostęp uzyskany 13 listopada 2019 r.).

[12] Oracle Corporation, "JDK-8146115: Poprawa wykrywania kontenerów Docker i wykorzystywania konfiguracji zasobów", 16 września 2019 r. (Online). Dostępne: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (Dostęp uzyskany 13 listopada 2019 r.).

[13] Oracle Corporation, "JEP 238: Multi-Release JAR Files", 22 czerwca 2017. (Online). Dostępne: http://openjdk.java.net/jeps/238. (Dostęp do 13 listopada 2019 r.).

[14] Oracle Corporation, "JEP 197: Segmented Code Cache", kwiecień 28, 2017. (Online). Dostępne: http://openjdk.java.net/jeps/197. (Dostęp z dnia 13 listopada 2019 r.)

[15] Oracle Corporation, "JEP 254: Compact Strings", 18 maja 2019 r. (Online). Dostępne: http://openjdk.java.net/jeps/254. Data dostępu: 13 listopada 2019 r.

[16] Oracle Corporation, "JEP 310: Application Class-Data Sharing", 17 sierpnia 2018. (Online). Dostępne: https://openjdk.java.net/jeps/310. (Ostatni dostęp 13 listopada 2019 r.).

[17] Oracle Corporation, "JEP 312: Thread-Local Handshakes", 21 sierpnia 2019. (Online). Dostępne: https://openjdk.java.net/jeps/312. (Dostęp uzyskany 13 listopada 2019 r.).

[18] Oracle Corporation, "JDK-8198756: Leniwa alokacja wątków kompilatora", 29 października 2018 r. (Online). Dostępne: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (Dostęp uzyskano 13 listopada 2019 r.).

[19] Oracle Corporation, "JEP 193: Variable Handles", sierpień 17, 2017. (Online). Dostępne: https://openjdk.java.net/jeps/193. (Ostatni dostęp: 13 listopada 2019 r.).

[20] Oracle Corporation, "JEP 269: Convenience Factory Methods for Collections", 26 czerwca 2017. (Online). Dostępne: https://openjdk.java.net/jeps/269. (Dostęp z dnia 13 listopada 2019 r.).

[21] Oracle Corporation, "JEP 285: Spin-Wait Hints", 20 sierpnia 2017. (Online). Dostępne: https://openjdk.java.net/jeps/285. (Dostęp do 13 listopada 2019 r.).

[22] Oracle Corporation, "JEP 321: HTTP Client (Standardowa)," 27 września 2018 r. (Online). Dostępne: https://openjdk.java.net/jeps/321. (Dostęp 13 listopada 2019 r.).