Důvody přechodu na Javu 11 a novější
Otázka není, pokud byste měli přejít na Javu 11 nebo novější verzi, ale kdy. V následujících několika letech se už Java 8 nebude podporovat a uživatelé budou muset přejít na Javu 11 nebo novější. Zastáváme názor, že přechod na Javu 11 s sebou nese výhody, a doporučujeme týmům přejít co nejdříve.
Od Javy 8 došlo k vylepšení a přidání nových funkcí. Rozhraní API zaznamenalo významné doplnění a úpravy a přináší vylepšení, která zlepšují spuštění, výkon a využití paměti.
Přechod na Javu 11
Přechod na Javu 11 je možné provést postupně. V kódu se nemusí používat moduly Java, aby mohl využívat Javu 11. Javu 11 je možné využít ke spouštění kódu vyvinutého a sestaveného s využitím sady JDK 8. Existuje však několik potenciálních problémů souvisejících primárně se zastaralým rozhraním API, zaváděcími programy tříd a reflexí.
Skupina Microsoft Java Engineering Group obsahuje průvodce přechodem z Javy 8 na Javu 11. Platforma Java, edice Standard Průvodce migrací Oracle JDK 9 a Stav systému modulů: Kompatibilita a migrace jsou další užitečné příručky.
Základní změny mezi Javou 8 a 11
Tato část nevypíše všechny změny provedené ve verzích Java 9 [1], 10 [2] a 11 [3]. Zdůrazněné jsou změny ovlivňující výkon, diagnostiku a produktivitu.
Moduly [4]
Moduly řeší problémy s konfigurací a zapouzdřením, které se obtížně spravují v rozsáhlých aplikacích využívajících cesty ke třídám. Modul je samostatná kolekce tříd a rozhraní Java a souvisejících prostředků.
Moduly umožňují přizpůsobit konfigurace modulů runtime obsahující pouze komponenty, které aplikace vyžaduje. Tímto přizpůsobením se sníží využití paměti a umožní statické propojení aplikace pomocí nástroje jlink do vlastního modulu runtime pro nasazení. Toto nižší využití paměti může být užitečné zejména v architektuře mikroslužeb.
Prostředí JVM dokáže moduly využívat interně tak, aby se zefektivnilo načítání tříd. Výsledkem je menší, jednodušší a rychleji spustitelný modul runtime. Techniky optimalizace, pomocí kterých prostředí JVM zvyšuje výkon aplikací, můžou být efektivnější, protože moduly kódují komponenty, které třídy vyžadují.
Programátorům moduly pomáhají vynucovat silné zapouzdření tím, že vyžadují explicitní deklaraci balíčků, které modul exportuje, a požadovaných komponent a že omezují reflektivní přístup. Tato úroveň zapouzdření poskytuje vyšší zabezpečení a snadnější údržbu aplikací.
Aplikace můžou dál využívat cesty ke třídám a nemusí kvůli přechodu na Javu 11 přecházet na moduly.
Profilace a diagnostika
Java Flight Recorder [5]
Nástroj Java Flight Recorder (JFR) shromažďuje diagnostická data a data profilace ze spuštěných aplikací v Javě. Nástroj JFR má minimální vliv na spuštěné aplikace v Javě. Shromážděná data je pak možné analyzovat pomocí nástroje Java Mission Control (JMC) a dalších nástrojů. Zatímco v Javě 8 byly nástroje JFR a JMC komerčními funkcemi, v Javě 11 jsou oba open source.
Java Mission Control [6]
Java Mission Control (JMC) poskytuje grafické zobrazení dat shromážděných nástrojem Java Flight Recorder (JFR) a je open source v Javě 11. Kromě obecných informací o spuštěné aplikaci umožňuje JMC uživateli přejít k podrobnostem dat. Pomocí nástrojů JFR a JMC je možné diagnostikovat problémy s modulem runtime, jako jsou nevrácení paměti, režijní náklady související s uvolňováním paměti, horké metody, kritické body vláken nebo blokování vstupně-výstupních operací.
Jednotné protokolování [7]
Java 11 má pro všechny komponenty prostředí JVM společný systém protokolování. Tento jednotný systém protokolování umožňuje uživatelům definovat, které komponenty a do jaké úrovně se mají protokolovat. Toto podrobné protokolování je užitečné při provádění analýzy původní příčiny v případě selhání prostředí JVM a při diagnostice problémů s výkonem v produkčním prostředí.
Profilace haldy s nízkou režií [8]
Do rozhraní Java Virtual Machine Tool Interface (JVMTI) se přidalo nové rozhraní API pro vzorkování přidělení haldy Javy. Toto vzorkování má nízké režijní náklady a je možné ho povolit nepřetržitě. Přidělení haldy je možné monitorovat pomocí nástroje Java Flight Recorder (JFR), ale metoda vzorkování v nástroji JFR funguje pouze pro přidělení. V implementaci nástroje JFR také můžou některá přidělení chybět. Vzorkování haldy v Javě 11 naproti tomu může poskytovat informace o aktivních i neaktivních objektech.
Dodavatelé APM tuto novou funkci začínají využívat a technická skupina pro Javu zkoumá její možné využití v nástrojích pro monitorování výkonu Azure.
StackWalker [9]
Při protokolování se často využívá získání snímku zásobníku aktuálního vlákna. Problémem je, jestli vůbec a v jakém rozsahu se má trasování zásobníku protokolovat. Někdo například může chtít zobrazit trasování zásobníku pouze pro určitou výjimku vyvolanou metodou. Třída StackWalker (přidaná v Javě 9) poskytuje snímek zásobníku a nabízí metody, které programátorům poskytují důkladnou kontrolu nad využíváním trasování zásobníku.
Uvolňování paměti [10]
Následující uvolňování paměti jsou k dispozici v Javě 11: Serial, Parallel, Garbage-First a Epsilon. Výchozím systémem uvolňování paměti v Javě 11 je systém uvolňování paměti Garbage-First (G1GC).
Pro plnost zde uvádíme další tři systémy uvolňování paměti. Systém uvolňování paměti Z (ZGC) je souběžný systém uvolňování paměti s nízkou latencí, který se pokouší držet prodlevu pod 10 ms. ZGC je v Javě 11 k dispozici jako experimentální funkce. Shenandoah je systém uvolňování paměti s krátkými prodlevami, který omezuje prodlevy systému uvolňování paměti tím, že u spuštěného programu v Javě provádí souběžně několikanásobné uvolňování paměti. Shenandoah je experimentální funkce v Javě 12, existují však zpětné porty pro Javu 11. Systém uvolňování paměti Concurrent Mark and Sweep (CMS) je k dispozici, ale od Javy 9 je zastaralý.
Prostředí JVM nastavuje výchozí hodnoty uvolňování paměti pro průměrný případ použití. Aby se zajistila optimální propustnost nebo latence, tyto výchozí hodnoty a další nastavení uvolňování paměti je často nutné vyladit podle požadavků konkrétní aplikace. Ke správnému ladění uvolňování paměti jsou potřeba důkladné znalosti uvolňování paměti, které vám může poskytnout technická skupina Microsoftu pro Javu.
G1GC
Výchozím systémem uvolňování paměti v Javě 11 je systém uvolňování paměti G1 (G1GC). Cílem systému G1GC je dosáhnout rovnováhy mezi latencí a propustností. Systém uvolňování paměti G1 se snaží dosáhnout vysoké propustnosti tím, že s vysokou pravděpodobností dosahuje cílové prodlevy. G1GC je navržený tak, aby se vyhnul úplným kolekcím, ale pokud souběžné kolekce nemohou uvolnit paměť dostatečně rychle, dojde k záložnímu úplnému uvolňování paměti. Při úplném uvolnění paměti se používá stejný počet paralelních pracovních vláken, jako je počet nových a smíšených kolekcí.
Systém uvolňování paměti Parallel
Systém uvolňování paměti Parallel je výchozím systémem uvolňování paměti v Javě 8. Systém uvolňování paměti Parallel ke zrychlení uvolňování paměti využívá několik vláken.
Epsilon [11]
Systém uvolňování paměti Epsilon zpracovává přidělení, ale neuvolňuje žádnou paměť. Když dojde k vyčerpání haldy, prostředí JVM se vypne. Systém Epsilon je vhodný pro krátkodobé služby a aplikace, které uvolňování paměti nepotřebují.
Vylepšení kontejnerů Dockeru [12]
Před Javou 10 prostředí JVM nedokázalo rozpoznat omezení paměti a procesoru nastavená pro kontejner. V Javě 8 například prostředí JVM nastavuje výchozí maximální velikost haldy na ¼ fyzické paměti základního hostitele. Od Javy 10 prostředí JVM k nastavení limitů paměti a procesoru používá omezení nastavená skupinami pro správu kontejnerů (viz poznámka níže). Například výchozí maximální velikost haldy je ¼ limitu paměti kontejneru (například 500 MB v případě kontejneru -m2G).
Přidaly se také možnosti prostředí JVM, které uživatelům kontejnerů Dockeru poskytují důkladnou kontrolu nad velikostí systémové paměti, která se použije pro haldu Javy.
Tato podpora je ve výchozím nastavení povolená a je k dispozici pouze na platformách založených na Linuxu.
Poznámka
Většina práce související s podporou skupin pro správu kontejnerů se zpětně portovala pro Javu 8 ve verzi jdk8u191. Další vylepšení se nemusí nutně zpětně portovat pro verzi 8.
Soubory jar s více verzemi [13]
V Javě 11 je možné vytvořit soubor JAR, který obsahuje několik verzí souborů tříd specifických pro konkrétní verze Javy. Soubory JAR s více verzemi umožňují vývojářům knihoven zajistit podporu několika verzí Javy, aniž by museli dodávat několik verzí souborů JAR. Pro příjemce těchto knihoven soubory JAR s více verzemi řeší problém s výběrem konkrétních souborů JAR pro konkrétní cíle modulu runtime.
Různá vylepšení výkonu
Následující změny prostředí JVM mají přímý vliv na výkon.
JEP 197: Segmentovaná mezipaměť kódu [14] – rozdělí mezipaměť kódu do různých segmentů. Tato segmentace poskytuje lepší kontrolu nad využitím paměti v prostředí JVM, zkracuje dobu potřebnou k prohledávání zkompilovaných metod, výrazně snižuje fragmentaci mezipaměti kódu a zvyšuje výkon.
JEP 254: Komprimační řetězce [15] – změní vnitřní reprezentaci řetězce ze dvou bajtů na znak na jeden nebo dva bajty na znak v závislosti na kódování znaků. Vzhledem k tomu, že většina řetězců obsahuje znaky v kódování ISO-8859-1/Latin-1, touto změnou se efektivně snižuje množství místa požadované k uložení řetězce na polovinu.
JEP 310: Sdílení aplikací Class-Data [16] – sdílení Class-Data snižuje dobu spuštění tím, že umožňuje archivované třídy mapovat za běhu paměť. Sdílení dat tříd v rámci aplikace rozšiřuje sdílení dat tříd tím, že umožňuje umisťovat třídy aplikací do archivu CDS. Když několik prostředí JVM sdílí stejný soubor archivu, paměť se uloží a tím se zkrátí celková doba odezvy systému.
JEP 312: Thread-Local Handshakes [17] – umožňuje spustit zpětné volání na vláknech bez provedení globálního bezpečného bodu virtuálního počítače, což virtuálnímu počítači pomáhá dosáhnout nižší latence snížením počtu globálních bezpečných bodů.
Opožděné přidělování vláken kompilátoru [18] – V režimu vrstvené kompilace virtuální počítač spustí velký počet vláken kompilátoru. Tento režim je výchozím režimem v systémech s velkým počtem procesorů. Tato vlákna se vytváří bez ohledu na dostupnou paměť nebo počet požadavků na kompilaci. Vlákna spotřebovávají paměť, i když jsou nečinná (což je téměř pořád), což vede k neefektivnímu využití prostředků. Za účelem vyřešení tohoto problému se implementace změnila tak, aby se při spouštění spustilo pouze jedno vlákno kompilátoru každého typu. Spouštění dalších vláken a vypínání nepoužívaných vláken probíhá dynamicky.
Následující změny základních knihoven mají vliv na výkon nového nebo upraveného kódu.
JEP 193: Proměnné úchyty [19] – definuje standardní prostředky pro vyvolání ekvivalentů různých operací java.util.concurrent.atomic a sun.misc.Nebezpečných operací s poli objektů a prvky pole, standardní sadu operací plotu pro jemně odstupňovanou kontrolu řazení paměti a standardní operaci dosažitelnosti plotu, která zajistí, aby odkazovaný objekt zůstal silně dosažitelný.
JEP 269: Metody továrny pro pohodlí pro kolekce [20] – Definuje rozhraní API knihovny, aby bylo vhodné vytvářet instance kolekcí a map s malým počtem prvků. Statické metody pro vytváření objektů v rozhraních kolekcí vytvářejí kompaktní instance kolekcí, které neumožňují úpravy. Tyto instance jsou ze své podstaty efektivnější. Rozhraní API vytváří kolekce, které jsou kompaktně reprezentované a nemají třídu obálky.
JEP 285: Spin-Wait Nápovědy [21] – poskytuje rozhraní API, které umožňuje javě naznačovat systém za běhu, který je ve smyčce spin. Určité hardwarové platformy využívají softwarovou indikaci vláken v zaneprázdněném a čekajícím stavu.
JEP 321: Klient HTTP (Standard) [22]- Poskytuje nové rozhraní API klienta HTTP, které implementuje http/2 a WebSocket a může nahradit starší verzi rozhraní HTTPURLConnection API.
Reference
[1] Oracle Corporation, "Java Development Kit 9 – zpráva k vydání verze", (Online). k dispozici: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html (otevřeno: 13. listopadu 2019)
[2] Oracle Corporation, "Java Development Kit 10 Release Notes", (Online). k dispozici: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html (otevřeno: 13. listopadu 2019)
[3] Oracle Corporation, "Java Development Kit 11 Release Notes" (Online). k dispozici: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html (otevřeno: 13. listopadu 2019)
[4] Oracle Corporation, "Project Jigsaw", září 22, 2017. (Online). k dispozici: http://openjdk.java.net/projects/jigsaw/ (otevřeno: 13. listopadu 2019)
[5] Oracle Corporation, "JEP 328: Flight Recorder", září 9, 2018. (online), k dispozici: http://openjdk.java.net/jeps/328 (otevřeno: 13. listopadu 2019)
[6] Oracle Corporation, "Mission Control", 25. dubna 2019. (online), k dispozici: https://wiki.openjdk.java.net/display/jmc/Main (otevřeno: 13. listopadu 2019)
[7] Oracle Corporation, "JEP 158: Unified JVM Logging," 14. února 2019. (online), k dispozici: http://openjdk.java.net/jeps/158 (otevřeno: 13. listopadu 2019)
[8] Oracle Corporation, "JEP 331: Low-Overhead Profilace haldy", 5. září 2018. (online), k dispozici: http://openjdk.java.net/jeps/331 (otevřeno: 13. listopadu 2019)
[9] Oracle Corporation, "JEP 259: Stack-Walking API," 18. července 2017. (online), k dispozici: http://openjdk.java.net/jeps/259 (otevřeno: 13. listopadu 2019)
[10] Oracle Corporation, "JEP 248: Make G1 the Default Garbage Collector," 12. září 2017. (online), k dispozici: http://openjdk.java.net/jeps/248 (otevřeno: 13. listopadu 2019)
[11] Oracle Corporation, "JEP 318: Epsilon: A No-Op Garbage Collector," 24. září 2018. (online), k dispozici: http://openjdk.java.net/jeps/318 (otevřeno: 13. listopadu 2019)
[12] Oracle Corporation, "JDK-8146115: Zlepšení detekce kontejnerů Dockeru a využití konfigurace prostředků", 16. září 2019. (online), k dispozici: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115 (otevřeno: 13. listopadu 2019)
[13] Oracle Corporation, "JEP 238: Multi-Release JAR Files," 22. června 2017. (online), k dispozici: http://openjdk.java.net/jeps/238 (otevřeno: 13. listopadu 2019)
[14] Oracle Corporation, "JEP 197: Segmented Code Cache", 28. dubna 2017. (online), k dispozici: http://openjdk.java.net/jeps/197 (otevřeno: 13. listopadu 2019)
[15] Oracle Corporation, "JEP 254: Kompaktní řetězce", 18. května 2019. (online), k dispozici: http://openjdk.java.net/jeps/254 (otevřeno: 13. listopadu 2019)
[16] Oracle Corporation, "JEP 310: Application Class-Data Sharing," 17. srpna 2018. (online), k dispozici: https://openjdk.java.net/jeps/310 (otevřeno: 13. listopadu 2019)
[17] Oracle Corporation, "JEP 312: Thread-Local Handshakes," 21. srpna 2019. (online), k dispozici: https://openjdk.java.net/jeps/312 (otevřeno: 13. listopadu 2019)
[18] Oracle Corporation, "JDK-8198756: Opožděné přidělování vláken kompilátoru", 29. října 2018. (online), k dispozici: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756 (otevřeno: 13. listopadu 2019)
[19] Oracle Corporation, "JEP 193: Variable Handles," 17. srpna 2017. (online), k dispozici: https://openjdk.java.net/jeps/193 (otevřeno: 13. listopadu 2019)
[20] Oracle Corporation, "JEP 269: Metody pro práci s kolekcemi", 26. června 2017. (online), k dispozici: https://openjdk.java.net/jeps/269 (otevřeno: 13. listopadu 2019)
[21] Oracle Corporation, "JEP 285: Spin-Wait Hints," 20. srpna 2017. (online), k dispozici: https://openjdk.java.net/jeps/285 (otevřeno: 13. listopadu 2019)
[22] Oracle Corporation, "JEP 321: HTTP Client (Standard)," 27. září 2018. (online), k dispozici: https://openjdk.java.net/jeps/321 (otevřeno: 13. listopadu 2019)