Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
A questão não é se deves mudar para Java 11 ou uma versão posterior, mas quando. Nos próximos anos, o Java 8 deixará de ser suportado e os utilizadores terão de migrar para o Java 11 ou posterior. Defendemos que há benefícios em migrar para Java 11 e incentivamos as equipas a fazê-lo o mais rapidamente possível.
Desde o Java 8, foram adicionadas novas funcionalidades e foram feitas melhorias. Há adições e modificações notórias à API, e melhorias que melhoram o arranque, o desempenho e o uso de memória.
Transição para Java 11
A transição para Java 11 pode ser feita de forma gradual. Não é obrigatório que o código utilize módulos Java para correr no Java 11. Java 11 pode ser usado para executar código desenvolvido e construído com JDK 8. Mas há alguns problemas potenciais, principalmente relacionados com APIs obsoletas, carregadores de classes e reflexão.
O Grupo de Engenharia Java da Microsoft tem um guia para a transição do Java 8 para o Java 11. The Guia de Migração da Plataforma Java, Edição Standard Oracle JDK 9 e O Estado do Sistema de Módulos: Compatibilidade e Migração são outros guias úteis.
Mudanças de alto nível entre Java 8 e 11
Esta secção não enumera todas as alterações feitas nas versões Java 9 [1], 10 [2] e 11 [3]. São destacadas alterações que impactam o desempenho, diagnósticos e produtividade.
Módulos [4]
Os módulos abordam questões de configuração e encapsulamento que são difíceis de gerir em aplicações de grande escala a correr no classpath. Um módulo é uma coleção auto-descritiva de classes e interfaces Java, bem como recursos relacionados.
Os módulos tornam possível personalizar configurações de execução que contêm apenas os componentes necessários por uma aplicação. Esta personalização cria uma área de utilização menor e permite que uma aplicação seja ligada estaticamente, usando jlink, a um runtime personalizado para implementação. Esta pegada menor pode ser particularmente útil numa arquitetura de microserviços.
Internamente, a JVM consegue tirar partido dos módulos de forma a tornar o carregamento de classes mais eficiente. O resultado é um tempo de execução mais pequeno, leve e rápido a arrancar. As técnicas de otimização usadas pela JVM para melhorar o desempenho das aplicações podem ser mais eficazes porque os módulos codificam quais os componentes que uma classe necessita.
Para os programadores, os módulos ajudam a impor uma encapsulação forte exigindo uma declaração explícita de quais pacotes um módulo exporta e quais os componentes que necessita, e restringindo o acesso reflexivo. Este nível de encapsulamento torna uma aplicação mais segura e fácil de manter.
Uma aplicação pode continuar a usar o classpath e não precisa de transitar para módulos como requisito para correr em Java 11.
Perfilamento e diagnóstico
Gravador de Voo Java [5]
O Java Flight Recorder (JFR) recolhe dados de diagnóstico e perfis de uma aplicação Java em funcionamento. JFR tem pouco impacto numa aplicação Java em execução. Os dados recolhidos podem então ser analisados com o Java Mission Control (JMC) e outras ferramentas. Enquanto o JFR e o JMC eram funcionalidades comerciais no Java 8, ambos são open source no Java 11.
Controlo de Missão Java [6]
O Java Mission Control (JMC) fornece uma visualização gráfica dos dados recolhidos pelo Java Flight Recorder (JFR) e é open source em Java 11. Para além da informação geral sobre a aplicação em execução, o JMC permite ao utilizador aprofundar os dados. JFR e JMC podem ser usados para diagnosticar problemas em tempo de execução, como fugas de memória, sobrecarga de GC, métodos hot, gargalos de thread e bloqueio de I/O.
Registo unificado [7]
O Java 11 tem um sistema comum de registo para todos os componentes da JVM. Este sistema unificado de registo permite ao utilizador definir que componentes registar e a que nível. Este registo detalhado é útil para realizar análises da causa raiz em crashes de JVM e para diagnosticar problemas de desempenho num ambiente de produção.
Perfil de heap de baixo overhead [8]
Foi adicionada uma nova API à Java Virtual Machine Tool Interface (JVMTI) para amostrar alocações de heap Java. A amostragem tem um baixo custo operacional e pode ser ativada continuamente. Embora a alocação do heap possa ser monitorizada com o Java Flight Recorder (JFR), o método de amostragem do JFR funciona apenas para alocações. A implementação do JFR também pode não captar as alocações. Em contraste, a amostragem de heap no Java 11 pode fornecer informação tanto sobre objetos vivos como mortos.
Os fornecedores de Monitorização de Desempenho de Aplicações (APM) estão a começar a utilizar esta nova funcionalidade e o Java Engineering Group está a investigar a sua potencial utilização com ferramentas de monitorização de desempenho do Azure.
StackWalker [9]
Obter um snapshot da pilha para o thread atual é frequentemente usado ao registar. O problema é quanto do traço da pilha deve ser registado, e se deve ou não registar o traço da pilha. Por exemplo, pode-se querer ver o rastreio de pilha apenas para uma determinada exceção de um método. A classe StackWalker (adicionada no Java 9) oferece um instantâneo da pilha e métodos que dão ao programador um controlo minucioso sobre como consumir o rastreio da pilha.
Recolha de lixo [10]
Os seguintes coletores de lixo estão disponíveis em Java 11: Serial, Parallel, Garbage-First e Epsilon. O coletor de lixo padrão no Java 11 é o Garbage First Garbage Collector (G1GC).
Aqui são mencionados outros três colecionadores para maior completude. O Z Garbage Collector (ZGC) é um coletor concorrente de baixa latência que tenta manter os tempos de pausa abaixo de 10ms. O ZGC está disponível como funcionalidade experimental em Java 11. O coletor Shenandoah é um coletor de pausa curta que reduz os tempos de pausa do Garbage Collection (GC) ao realizar mais recolha de lixo paralelamente ao programa Java em execução. O Shenandoah é uma funcionalidade experimental no Java 12, mas existem backports para o Java 11. O Concurrent Mark and Sweep collector (CMS) está disponível, mas está obsoleto desde o Java 9.
A JVM define os padrões de GC para o caso de uso médio. Frequentemente, estes valores predefinidos, e outras definições do GC, precisam de ser ajustados para um rendimento ou latência ótimos, de acordo com os requisitos da aplicação. Afinar corretamente o GC requer um conhecimento profundo do GC, a experiência que o Microsoft Java Engineering Group fornece.
G1GC
O coletor de lixo padrão no Java 11 é o coletor de lixo G1 (G1GC). O objetivo do G1GC é encontrar um equilíbrio entre latência e rendimento. O coletor de lixo G1 tenta alcançar um alto débito cumprindo os objetivos de tempo de pausa com alta probabilidade. O G1GC foi concebido para evitar coleções completas, mas quando as coleções concorrentes não conseguem recuperar memória suficientemente rápido, ocorre um recurso. O GC completo utiliza o mesmo número de threads de trabalho paralelas que as coleções jovens e mistas.
GC paralelo
O coletor paralelo é o coletor padrão no Java 8. O GC paralelo é um coletor de throughput que utiliza múltiplos threads para acelerar a recolha de lixo.
Epsilon [11]
O coletor de lixo Epsilon trata das alocações, mas não recupera qualquer memória. Quando o heap se esgota, a JVM desliga-se. O Epsilon é útil para serviços de curta duração e para aplicações conhecidas por serem livres de lixo.
Melhorias para contentores docker [12]
Antes do Java 10, as restrições de memória e CPU definidas num contentor não eram reconhecidas pela JVM. No Java 8, por exemplo, a JVM irá predefinir o tamanho máximo do heap para 1/4 da memória física do host subjacente. A partir do Java 10, a JVM utiliza restrições definidas por grupos de controlo de contentores (cgroups) para definir os limites de memória e CPU (ver nota abaixo). Por exemplo, o tamanho máximo padrão do heap é 1/4 do limite de memória do contentor (por exemplo, 500MB para -m2G).
Foram também adicionadas Opções JVM para dar aos utilizadores de contentores Docker controlo detalhado sobre a quantidade de memória do sistema que será usada no heap Java.
Este suporte está ativado por padrão e está disponível apenas em plataformas baseadas em Linux.
Observação
A maior parte do trabalho de habilitação do cgroup foi retroportada para o Java 8 no jdk8u191. Melhorias adicionais podem não ser necessariamente transferidas para o 8.
Ficheiros jar multi-lançamento [13]
É possível no Java 11 criar um ficheiro jar que contenha múltiplas versões específicas de Java dos ficheiros de classe. Os ficheiros jar de múltiplas versões permitem aos desenvolvedores de bibliotecas suportar múltiplas versões de Java sem terem de enviar múltiplas versões de ficheiros jar. Para o consumidor destas bibliotecas, os ficheiros de jar multi-release resolvem o problema de ter de associar ficheiros de jar específicos a alvos de runtime específicos.
Melhorias de desempenho diversas
As alterações seguintes à JVM têm um impacto direto no desempenho.
JEP 197: Cache de Código Segmentado [14] - Divide o cache de código em segmentos distintos. Esta segmentação proporciona melhor controlo da área de memória da JVM, reduz o tempo de varrimento dos métodos compilados, diminui significativamente a fragmentação da cache de código e melhora o desempenho.
JEP 254: Compact Strings [15] - Altera a representação interna de uma string de dois bytes por caractere para um ou dois bytes por caractere, dependendo da codificação do caractere. Como a maioria das Strings contém caracteres ISO-8859-1/Latin-1, esta alteração reduz efetivamente para metade o espaço necessário para armazenar uma String.
JEP 310: Partilha de Dados de Classe de Aplicações [16] - A Partilha de Dados de Classe diminui o tempo de arranque ao permitir que as classes arquivadas sejam mapeadas na memória durante o tempo de execução. A Partilha de Dados de Classes de Aplicações amplia a partilha de dados de classes ao permitir que as classes de aplicação sejam adicionadas ao arquivo de partilha. Quando várias JVMs partilham o mesmo ficheiro de arquivo, a memória é guardada e o tempo de resposta global do sistema melhora.
JEP 312: Thread-Local Handshakes [17] - Torna possível executar um callback em threads sem realizar um ponto de segurança global da VM, o que ajuda a VM a alcançar uma latência menor ao reduzir o número de pontos de segurança globais.
Alocação Preguiçosa de Threads do Compilador [18] - No modo de compilação em camadas, a VM inicia um grande número de threads do compilador. Este modo é o padrão em sistemas com muitos CPUs. Estas threads são criadas independentemente da memória disponível ou do número de pedidos de compilação. As threads consomem memória mesmo quando estão inativas (o que acontece quase sempre), o que leva a uma utilização ineficiente dos recursos. Para resolver este problema, a implementação foi alterada para iniciar apenas um thread compilador de cada tipo durante o arranque. Iniciar threads adicionais e encerrar threads não utilizados é tratado dinamicamente.
As alterações seguintes às bibliotecas principais têm impacto no desempenho de código novo ou modificado.
JEP 193: Variáveis Handles [19] - Define um meio padrão para invocar os equivalentes de várias operações java.util.concurrent.atomic e sun.misc.Unsafe sobre campos de objeto e elementos de array, um conjunto padrão de operações de cerca para controlo detalhado da ordenação de memória, e uma operação padrão de reachability-fence para garantir que um objeto referenciado permanece fortemente acessível.
JEP 269: Métodos de Fábrica de Conveniência para Coleções [20] - Define APIs de biblioteca para tornar conveniente criar instâncias de coleções e mapas com um pequeno número de elementos. Os métodos de fábrica estática nas interfaces de coleção que criam instâncias de coleção compactas e não modificáveis. Estas instâncias são inerentemente mais eficientes. As APIs criam coleções que são representadas de forma compacta e não possuem uma classe wrapper.
JEP 285: Spin-Wait Hints [21] - Fornece uma API que permite ao Java indicar ao sistema de execução que está num ciclo de espera ativa. Certas plataformas de hardware beneficiam da indicação por software de que um thread está em estado de espera ocupada.
JEP 321: Cliente HTTP (Standard) [22] - Fornece uma nova API cliente HTTP que implementa HTTP/2 e WebSocket e pode substituir a antiga API HttpURLConnection.
Referências
[1] Oracle Corporation, "Notas de Lançamento do Java Development Kit 9," (Online). Disponível: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (Consultado a 13 de novembro de 2019).
[2] Oracle Corporation, "Notas de Lançamento do Java Development Kit 10," (Online). Disponível: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (Consultado a 13 de novembro de 2019).
[3] Oracle Corporation, "Notas de Lançamento do Java Development Kit 11," (Online). Disponível: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (Consultado a 13 de novembro de 2019).
[4] Oracle Corporation, "Project Jigsaw", 22 de setembro de 2017. (Online). Disponível: http://openjdk.java.net/projects/jigsaw/. (Consultado a 13 de novembro de 2019).
[5] Oracle Corporation, "JEP 328: Flight Recorder," 9 de setembro de 2018. (Online). Disponível: http://openjdk.java.net/jeps/328. (Consultado a 13 de novembro de 2019).
[6] Oracle Corporation, "Mission Control", 25 de abril de 2019. (Online). Disponível: https://wiki.openjdk.java.net/display/jmc/Main. (Consultado a 13 de novembro de 2019).
[7] Oracle Corporation, "JEP 158: Registo Unificado de JVM," 14 de fevereiro de 2019. (Online). Disponível: http://openjdk.java.net/jeps/158. (Consultado a 13 de novembro de 2019).
[8] Oracle Corporation, "JEP 331: Low-Overhead Heap Profiling," 5 de setembro de 2018. (Online). Disponível: http://openjdk.java.net/jeps/331. (Consultado a 13 de novembro de 2019).
[9] Oracle Corporation, "JEP 259: Stack-Walking API," 18 de julho de 2017. (Online). Disponível: http://openjdk.java.net/jeps/259. (Consultado a 13 de novembro de 2019).
[10] Oracle Corporation, "JEP 248: Faça do G1 o Coletor de Lixo Padrão," 12 de setembro de 2017. (Online). Disponível: http://openjdk.java.net/jeps/248. (Consultado a 13 de novembro de 2019).
[11] Oracle Corporation, "JEP 318: Epsilon: A No-Op Garbage Collector," 24 de setembro de 2018. (Online). Disponível: http://openjdk.java.net/jeps/318. (Consultado a 13 de novembro de 2019).
[12] Oracle Corporation, "JDK-8146115: Melhorar a deteção de contentores docker e a utilização da configuração de recursos," 16 de setembro de 2019. (Online). Disponível: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (Consultado a 13 de novembro de 2019).
[13] Oracle Corporation, "JEP 238: Ficheiros JAR Multi-Lançamento," 22 de junho de 2017. (Online). Disponível: http://openjdk.java.net/jeps/238. (Consultado a 13 de novembro de 2019).
[14] Oracle Corporation, "JEP 197: Cache de Código Segmentado," 28 de abril de 2017. (Online). Disponível: http://openjdk.java.net/jeps/197. (Consultado a 13 de novembro de 2019).
[15] Oracle Corporation, "JEP 254: Cordas Compactas," 18 de maio de 2019. (Online). Disponível: http://openjdk.java.net/jeps/254. (Consultado a 13 de novembro de 2019).
[16] Oracle Corporation, "JEP 310: Partilha de Dados de Classe de Aplicação," 17 de agosto de 2018. (Online). Disponível: https://openjdk.java.net/jeps/310. (Consultado a 13 de novembro de 2019).
[17] Oracle Corporation, "JEP 312: Thread-Local Handshakes," 21 de agosto de 2019. (Online). Disponível: https://openjdk.java.net/jeps/312. (Consultado a 13 de novembro de 2019).
[18] Oracle Corporation, "JDK-8198756: Alocação preguiçosa de threads do compilador," 29 de outubro de 2018. (Online). Disponível: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (Consultado a 13 de novembro de 2019).
[19] Oracle Corporation, "JEP 193: Variáveis Handles," 17 de agosto de 2017. (Online). Disponível: https://openjdk.java.net/jeps/193. (Consultado a 13 de novembro de 2019).
[20] Oracle Corporation, "JEP 269: Métodos de Fábrica de Conveniência para Coleções," 26 de junho de 2017. (Online). Disponível: https://openjdk.java.net/jeps/269. (Consultado a 13 de novembro de 2019).
[21] Oracle Corporation, "JEP 285: Spin-Wait Hints", 20 de agosto de 2017. (Online). Disponível: https://openjdk.java.net/jeps/285. (Consultado a 13 de novembro de 2019).
[22] Oracle Corporation, "JEP 321: HTTP Client (Standard)," 27 de setembro de 2018. (Online). Disponível: https://openjdk.java.net/jeps/321. (Consultado a 13 de novembro de 2019).