Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La domanda non è se è necessario passare a Java 11 o versione successiva, ma quando. Nei prossimi anni Java 8 non sarà più supportato e gli utenti dovranno passare a Java 11 o versioni successive. Riteniamo che ci siano vantaggi per passare a Java 11 e incoraggiare i team a farlo il prima possibile.
A partire da Java 8 sono state aggiunte nuove funzionalità e sono stati apportati miglioramenti. Esistono aggiunte e modifiche evidenti all'API e sono disponibili miglioramenti che migliorano l'avvio, le prestazioni e l'utilizzo della memoria.
Transizione a Java 11
La transizione a Java 11 può essere eseguita in modo dettagliato. Non è necessario che il codice usi i moduli Java per l'esecuzione in Java 11. Java 11 può essere usato per eseguire codice sviluppato e compilato con JDK 8. Esistono tuttavia alcuni potenziali problemi, principalmente relativi all'API deprecata, ai caricatori di classi e alla reflection.
Il Microsoft Java Engineering Group ha una guida alla transizione da Java 8 a Java 11. Java Platform, Standard Edition Oracle JDK 9 Migration Guide e Lo stato del sistema di moduli: compatibilità e migrazione sono altre guide utili.
Modifiche generali tra Java 8 e 11
Questa sezione non enumera tutte le modifiche apportate nelle versioni Java 9 [1], 10 [2]e 11 [3]. Le modifiche che hanno un impatto sulle prestazioni, la diagnostica e la produttività sono evidenziate.
Moduli [4]
I moduli affrontano i problemi di configurazione e incapsulamento difficili da gestire in applicazioni su larga scala in esecuzione nel classpath. Un modulo è una raccolta autodescrittura di classi e interfacce Java e risorse correlate.
I moduli consentono di personalizzare le configurazioni di runtime che contengono solo i componenti richiesti da un'applicazione. Questa personalizzazione crea un footprint più piccolo e consente a un'applicazione di essere collegata in modo statico, usando jlink, in un runtime personalizzato per la distribuzione. Questo footprint più piccolo può essere particolarmente utile in un'architettura di microservizi.
Internamente, la JVM è in grado di sfruttare i vantaggi dei moduli in modo da rendere più efficiente il caricamento di classi. Il risultato è un runtime più piccolo, più leggero e veloce da avviare. Le tecniche di ottimizzazione usate dalla JVM per migliorare le prestazioni dell'applicazione possono essere più efficaci perché i moduli codificano i componenti necessari per una classe.
Per i programmatori, i moduli consentono di applicare l'incapsulamento sicuro richiedendo una dichiarazione esplicita dei pacchetti di un modulo esportato e dei componenti necessari e limitando l'accesso riflettente. Questo livello di incapsulamento rende un'applicazione più sicura e più facile da gestire.
Un'applicazione può continuare a usare il classpath e non deve passare ai moduli come prerequisito per l'esecuzione in Java 11.
Profilatura e diagnostica
Java Flight Recorder [5]
Java Flight Recorder (JFR) raccoglie i dati di diagnostica e profilatura da un'applicazione Java in esecuzione. JFR ha un impatto minimo su un'applicazione Java in esecuzione. I dati raccolti possono quindi essere analizzati con Java Mission Control (JMC) e altri strumenti. Mentre JFR e JMC erano funzionalità commerciali in Java 8, entrambe sono open source in Java 11.
Java Mission Control [6]
Java Mission Control (JMC) fornisce una visualizzazione grafica dei dati raccolti da Java Flight Recorder (JFR) ed è open source in Java 11. Oltre alle informazioni generali sull'applicazione in esecuzione, JMC consente all'utente di eseguire il drill-down dei dati. JFR e JMC possono essere usati per diagnosticare problemi di runtime, ad esempio perdite di memoria, sovraccarico GC, metodi ad accesso frequente, colli di bottiglia dei thread e I/O bloccanti.
Registrazione unificata [7]
Java 11 ha un sistema di registrazione comune per tutti i componenti della JVM. Questo sistema di registrazione unificato consente all'utente di definire quali componenti registrare e a quale livello. Questa registrazione con granularità fine è utile per eseguire l'analisi della causa radice sugli arresti anomali di JVM e per la diagnosi dei problemi di prestazioni in un ambiente di produzione.
Profilatura dell'heap a basso sovraccarico [8]
È stata aggiunta una nuova API all'interfaccia JVMTI (Java Virtual Machine Tool Interface) per il campionamento delle allocazioni dell'heap Java. Il campionamento può essere abilitato continuamente e presenta un ridotto carico di lavoro. Anche se l'allocazione dell'heap può essere monitorata con Java Flight Recorder (JFR), il metodo di campionamento in JFR funziona solo sulle allocazioni. L'implementazione JFR può anche perdere allocazioni. Al contrario, il campionamento dell'heap in Java 11 può fornire informazioni sugli oggetti attivi e non attivi.
I fornitori di Application Performance Monitoring (APM) stanno iniziando a usare questa nuova funzionalità e java Engineering Group sta analizzando il potenziale uso con gli strumenti di monitoraggio delle prestazioni di Azure.
StackWalker [9]
Il recupero di uno snapshot dello stack per il thread corrente viene spesso usato durante la registrazione. Il problema è la quantità di analisi dello stack da registrare e se registrare l'analisi dello stack. Ad esempio, è possibile che si voglia visualizzare l'analisi dello stack solo per una determinata eccezione da un metodo. La classe StackWalker (aggiunta in Java 9) fornisce uno snapshot dello stack e fornisce metodi che forniscono al programmatore un controllo granulare su come usare l'analisi dello stack.
Raccolta dei Rifiuti [10]
I Garbage Collector seguenti sono disponibili in Java 11: Serial, Parallel, Garbage-First ed Epsilon. Il Garbage Collector predefinito in Java 11 è Garbage First Garbage Collector (G1GC).
Altri tre agenti di raccolta sono menzionati qui per completezza. Z Garbage Collector (ZGC) è un agente di raccolta simultaneo a bassa latenza che tenta di mantenere i tempi di pausa di meno di 10 ms. ZGC è disponibile come funzionalità sperimentale in Java 11. L'agente di raccolta Shenandoah è un agente di raccolta a pausa ridotta che riduce i tempi di pausa GC eseguendo più Garbage Collection contemporaneamente al programma Java in esecuzione. Shenandoah è una funzionalità sperimentale in Java 12, ma esistono backport in Java 11. L'algoritmo di garbage collection Concurrent Mark and Sweep (CMS) è disponibile ma è stato deprecato a partire da Java 9.
JVM imposta le impostazioni predefinite GC per il caso d'uso medio. Spesso, queste impostazioni predefinite e altre impostazioni GC devono essere ottimizzate per una velocità effettiva o una latenza ottimali, in base ai requisiti dell'applicazione. L'ottimizzazione corretta del GC richiede una conoscenza approfondita del GC, competenze fornite dal gruppo microsoft java engineering .
G1GC
Il garbage collector predefinito in Java 11 è il G1 garbage collector (G1GC). L'obiettivo di G1GC è quello di trovare un equilibrio tra latenza e velocità effettiva. Il Garbage Collector G1 tenta di raggiungere una velocità effettiva elevata soddisfando gli obiettivi di tempo di pausa con probabilità elevata. G1GC è progettato per evitare raccolte complete, ma quando le raccolte simultanee non possono recuperare memoria abbastanza velocemente, si verificherà un GC completo di fallback. Il full GC usa lo stesso numero di thread di lavoro paralleli delle raccolte giovani e quelle miste.
GC parallelo
L'agente di raccolta parallela è l'agente di raccolta predefinito in Java 8. Parallel GC è un collettore di throughput che utilizza più thread per velocizzare la Garbage Collection.
Epsilon [11]
Epsilon Garbage Collector gestisce le allocazioni, ma non recupera alcuna memoria. La JVM verrà arrestata quando l'heap sarà esaurito. Epsilon è utile per i servizi di breve durata e per le applicazioni note per essere prive di problemi di garbage.
Miglioramenti per i contenitori Docker [12]
Prima di Java 10, i vincoli di memoria e CPU impostati in un contenitore non sono stati riconosciuti dalla JVM. In Java 8, ad esempio, la JVM predefinitorà le dimensioni massime dell'heap su 1/4 della memoria fisica dell'host sottostante. A partire da Java 10, la JVM usa i vincoli impostati dai gruppi di controllo dei contenitori (cgroup) per impostare i limiti di memoria e CPU (vedere la nota seguente). Ad esempio, la dimensione massima predefinita dell'heap è 1/4 del limite di memoria del contenitore , ad esempio 500 MB per -m2G.
Sono state aggiunte anche opzioni JVM per fornire agli utenti del contenitore Docker un controllo granulare sulla quantità di memoria di sistema che verrà usata per l'heap Java.
Questo supporto è abilitato per impostazione predefinita ed è disponibile solo nelle piattaforme basate su Linux.
Annotazioni
La maggior parte del lavoro di abilitazione di cgroup è stata backportata in Java 8 a partire da jdk8u191. Ulteriori miglioramenti potrebbero non essere necessariamente retroportati alla versione 8.
File JAR a più versioni [13]
In Java 11 è possibile creare un file jar che contiene più versioni specifiche della versione Java dei file di classe. I file JAR a più versioni consentono agli sviluppatori di librerie di supportare più versioni di Java senza dover distribuire più versioni di file JAR. Per il consumer di queste librerie, i file con estensione jar a più versioni risolvono il problema di dover associare file JAR specifici a destinazioni di runtime specifiche.
Miglioramenti delle prestazioni vari
Le modifiche seguenti alla JVM hanno un impatto diretto sulle prestazioni.
JEP 197: cache di codice segmentata [14] - Divide la cache del codice in segmenti distinti. Questa segmentazione offre un migliore controllo del footprint di memoria JVM, riduce il tempo di analisi dei metodi compilati, riduce significativamente la frammentazione della cache del codice e migliora le prestazioni.
JEP 254: stringhe compatta [15] - Modifica la rappresentazione interna di una stringa da due byte per char a uno o due byte per char, a seconda della codifica char. Poiché la maggior parte delle stringhe contiene caratteri ISO-8859-1/Latin-1, questa modifica dimezza effettivamente la quantità di spazio necessaria per archiviare una stringa.
JEP 310: Condivisione dei dati di classe dell'applicazione [16] - La Condivisione dei Dati di Classe riduce il tempo di avvio consentendo la mappatura della memoria delle classi archiviate durante l'esecuzione. La condivisione di applicazioni Class-Data estende la condivisione dei dati di classe consentendo l'inserimento delle classi dell'applicazione nell'archivio CDS. Quando più JVM condividono lo stesso file di archivio, la memoria viene salvata e il tempo di risposta complessivo del sistema migliora.
JEP 312: Thread-Local Handshakes [17] - Consente di eseguire un callback nei thread senza eseguire un punto di sicurezza globale della VM, che consente alla VM di ottenere una latenza inferiore riducendo il numero di punti di sicurezza globali.
Allocazione differita dei thread del compilatore [18] - In modalità di compilazione a livelli, la macchina virtuale avvia un numero elevato di thread del compilatore. Questa modalità è l'impostazione predefinita nei sistemi con molte CPU. Questi thread vengono creati indipendentemente dalla memoria disponibile o dal numero di richieste di compilazione. I thread consumano memoria anche quando sono inattive (che è quasi tutto il tempo), il che comporta un uso inefficiente delle risorse. Per risolvere questo problema, l'implementazione è stata modificata per avviare un solo thread del compilatore di ogni tipo durante l'avvio. L'avvio di thread aggiuntivi e l'arresto dei thread inutilizzati vengono gestiti in modo dinamico.
Le modifiche seguenti alle librerie principali hanno un impatto sulle prestazioni del codice nuovo o modificato.
JEP 193: Handle di Variabili [19] - Definisce un mezzo standard per richiamare gli equivalenti delle varie operazioni di java.util.concurrent.atomic e sun.misc.Unsafe sui campi degli oggetti e sugli elementi degli array, un set standard di operazioni di barriera per il controllo granulare dell'ordinamento della memoria e un'operazione standard di barriera per la raggiungibilità per garantire che un oggetto a cui si fa riferimento rimanga fortemente raggiungibile.
JEP 269: Convenience Factory Methods for Collections [20] - Definisce le API della libreria per semplificare la creazione di istanze di raccolte e mappe con un numero ridotto di elementi. Metodi factory statici nelle interfacce della raccolta che creano istanze di raccolta compatta e non modificabili. Queste istanze sono intrinsecamente più efficienti. Le API creano raccolte rappresentate in modo compatto e non hanno una classe wrapper.
JEP 285: Spin-Wait Hints [21] - Fornisce un'API che consente a Java di suggerire all'ambiente di runtime che si trova in un ciclo di rotazione. Alcune piattaforme hardware traggono vantaggio dall'indicazione software che un thread si trova in uno stato di attesa occupato.
JEP 321: Client HTTP (Standard) [22]- Fornisce una nuova API client HTTP che implementa HTTP/2 e WebSocket e può sostituire l'API HttpURLConnection legacy.
References
[1] Oracle Corporation, "Note sulla versione di Java Development Kit 9" (online). Disponibile: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (Accesso: 13 novembre 2019).
[2] Oracle Corporation, "Note sulla versione di Java Development Kit 10" (online). Disponibile: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (Accesso: 13 novembre 2019).
[3] Oracle Corporation, "Note sulla versione di Java Development Kit 11" (online). Disponibile: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (Accesso: 13 novembre 2019).
Oracle Corporation , "Project Jigsaw", 22 settembre 2017. (Online). Disponibile: http://openjdk.java.net/projects/jigsaw/. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 328: Flight Recorder", 9 settembre 2018. (Online). Disponibile: http://openjdk.java.net/jeps/328. (Accesso: 13 novembre 2019).
Oracle Corporation, "Mission Control", 25 aprile 2019. (Online). Disponibile: https://wiki.openjdk.java.net/display/jmc/Main. (Accesso: 13 novembre 2019).
Oracle Corporation, «JEP 158: Unified JVM Logging», 14 febbraio 2019. (Online). Disponibile: http://openjdk.java.net/jeps/158. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 331: Profilazione a basso consumo di risorse della memoria heap", 5 settembre 2018. (Online). Disponibile: http://openjdk.java.net/jeps/331. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 259: Stack-Walking API", 18 luglio 2017. (Online). Disponibile: http://openjdk.java.net/jeps/259. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 248: Make G1 the Default Garbage Collector", 12 settembre 2017. (Online). Disponibile: http://openjdk.java.net/jeps/248. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 318: Epsilon: A No-Op Garbage Collector", 24 settembre 2018. (Online). Disponibile: http://openjdk.java.net/jeps/318. (Accesso: 13 novembre 2019).
Oracle Corporation, "JDK-8146115: Migliorare il rilevamento dei contenitori Docker e l'utilizzo della configurazione delle risorse", 16 settembre 2019. (Online). Disponibile: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (Accesso: 13 novembre 2019).
[13] Oracle Corporation, "JEP 238: Multi-Release JAR Files", 22 giugno 2017. (Online). Disponibile: http://openjdk.java.net/jeps/238. (Accesso: 13 novembre 2019).
Oracle Corporation , "JEP 197: Segmented Code Cache", 28 aprile 2017. (Online). Disponibile: http://openjdk.java.net/jeps/197. (Accesso: 13 novembre 2019).
[15] Oracle Corporation, «JEP 254: Compact Strings», 18 maggio 2019. (Online). Disponibile: http://openjdk.java.net/jeps/254. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 310: Application Class-Data Sharing", 17 agosto 2018. (Online). Disponibile: https://openjdk.java.net/jeps/310. (Accesso: 13 novembre 2019).
Oracle Corporation, «JEP 312: Thread-Local Handshakes», 21 agosto 2019. (Online). Disponibile: https://openjdk.java.net/jeps/312. (Accesso: 13 novembre 2019).
Oracle Corporation, "JDK-8198756: l'allocazione differita dei thread del compilatore", 29 ottobre 2018. (Online). Disponibile: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 193: Variable Handles", 17 agosto 2017. (Online). Disponibile: https://openjdk.java.net/jeps/193. (Accesso: 13 novembre 2019).
Oracle Corporation , "JEP 269: Convenience Factory Methods for Collections", 26 giugno 2017. (Online). Disponibile: https://openjdk.java.net/jeps/269. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 285: Suggerimenti di attesa attiva", 20 agosto 2017. (Online). Disponibile: https://openjdk.java.net/jeps/285. (Accesso: 13 novembre 2019).
Oracle Corporation, "JEP 321: Client HTTP (Standard)," 27 settembre 2018. (Online). Disponibile: https://openjdk.java.net/jeps/321. (Accesso: 13 novembre 2019).