Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A questão não é se você deve mudar para Java 11 ou uma versão posterior, mas quando. Nos próximos anos, o Java 8 não terá mais suporte e os usuários precisarão migrar para Java 11 ou posterior. Argumentamos que há benefícios em mudar para Java 11 e incentivar as equipes a fazê-lo o mais rápido possível.
Desde o Java 8, novos recursos foram adicionados e aprimoramentos foram feitos. Há adições e modificações perceptíveis à API e há aprimoramentos que melhoram o uso de inicialização, desempenho e memória.
Transição para Java 11
A transição para Java 11 pode ser feita de maneira passo a passo. Não é necessário que o código use módulos Java para serem executados no Java 11. O Java 11 pode ser usado para executar o código desenvolvido e criado com o JDK 8. Mas há alguns problemas potenciais, principalmente em relação à API preterida, aos carregadores de classe e à reflexão.
O Grupo de Engenharia Java da Microsoft tem um guia para fazer a transição do Java 8 para o Java 11. A Plataforma Java, o Guia de Migração do Oracle JDK 9 da Edição Standard e o Estado do Sistema de Módulos: Compatibilidade e Migração são outros guias úteis.
Alterações de alto nível entre Java 8 e 11
Esta seção não enumera todas as alterações feitas nas versões java 9 [1], 10 [2] e 11 [3]. As alterações que afetam o desempenho, o diagnóstico e a produtividade são realçadas.
Módulos [4]
Os módulos abordam problemas de configuração e encapsulamento que são difíceis de gerenciar em aplicativos em grande escala em execução no classpath. Um módulo é uma coleção autodescrevendo classes e interfaces Java e recursos relacionados.
Os módulos possibilitam personalizar configurações de runtime que contêm apenas os componentes exigidos por um aplicativo. Essa personalização cria uma pegada menor e permite que um aplicativo seja vinculado estaticamente, usando jlink, em um ambiente de execução personalizado para implantação. Esse volume menor pode ser particularmente útil em uma arquitetura de microsserviços.
Internamente, a JVM é capaz de aproveitar os módulos de uma forma que torne o carregamento de classes mais eficiente. O resultado é um runtime menor, mais leve e mais rápido de iniciar. As técnicas de otimização usadas pela JVM para melhorar o desempenho do aplicativo podem ser mais eficazes porque os módulos codificam quais componentes uma classe requer.
Para programadores, os módulos ajudam a impor um encapsulamento forte, exigindo uma declaração explícita de quais pacotes um módulo exporta e quais componentes ele requer e restringindo o acesso reflexivo. Esse nível de encapsulamento torna um aplicativo mais seguro e fácil de manter.
Um aplicativo pode continuar a usar o classpath e não precisa fazer a transição para módulos como um requisito para execução no Java 11.
Criação de perfil e diagnóstico
Java Flight Recorder [5]
O Java Flight Recorder (JFR) coleta dados de diagnóstico e de análise de desempenho de um aplicativo Java que está sendo executado. O JFR tem pouco impacto em um aplicativo Java em execução. Os dados coletados podem então ser analisados com o JMC (Java Mission Control) e outras ferramentas. Enquanto JFR e JMC eram recursos comerciais no Java 8, ambos são de software livre no Java 11.
Controle de Missão Java [6]
O JMC (Java Mission Control) fornece uma exibição gráfica dos dados coletados pelo JFR (Java Flight Recorder) e é de software livre no Java 11. Além das informações gerais sobre o aplicativo em execução, o JMC permite que o usuário faça uma busca detalhada nos dados. JFR e JMC podem ser usados para diagnosticar problemas de tempo de execução, como vazamentos de memória, sobrecarga do GC, métodos críticos, gargalos de thread e E/S bloqueante.
Registro Unificado [7]
O Java 11 tem um sistema de log comum para todos os componentes da JVM. Esse sistema de registro em log unificado permite que o usuário defina quais componentes registrar em log e em que nível. Esse registro em log refinado é útil para executar a análise de causa raiz em falhas de JVM e para diagnosticar problemas de desempenho em um ambiente de produção.
Perfilamento de heap com baixa sobrecarga [8]
Uma nova API foi adicionada à Interface de Ferramenta da Máquina Virtual Java (JVMTI) para amostragem de alocações de heap Java. A amostragem tem baixa sobrecarga e pode ser ativada continuamente. Embora a alocação de heap possa ser monitorada 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 perder alocações. Por outro lado, a amostragem de heap no Java 11 pode fornecer informações sobre objetos ativos e mortos.
Os fornecedores do APM (Monitoramento de Desempenho de Aplicativos) estão começando a utilizar esse novo recurso e o Grupo de Engenharia java está investigando seu potencial uso com as ferramentas de monitoramento de desempenho do Azure.
StackWalker [9]
Obter um instantâneo da pilha para o thread atual geralmente é usado ao fazer log. O problema é quanto do rastreamento de pilha deve ser registrado e se ele deve ser registrado de fato. Por exemplo, alguém pode querer ver o rastreamento de pilha apenas para uma determinada exceção em um método. A classe StackWalker (adicionada em Java 9) fornece um instantâneo da pilha e fornece métodos que fornecem ao programador controle refinado sobre como consumir o rastreamento de pilha.
Coleta de lixo [10]
Os coletores de lixo a seguir estão disponíveis no Java 11: Serial, Parallel, Garbage-First e Epsilon. O coletor de lixo padrão no Java 11 é o coletor de lixo Garbage First (G1GC).
Três outros coletores são mencionados aqui para fins de completude. O ZGC (Coletor de Lixo Z) é um coletor simultâneo e de baixa latência que tenta manter os tempos de pausa abaixo de 10ms. O ZGC está disponível como um recurso experimental no Java 11. O coletor Shenandoah é um coletor de pausas curtas que reduz os tempos de pausa do GC realizando mais coleta de lixo simultaneamente com o programa Java em execução. Shenandoah é uma característica experimental no Java 12, mas há backports para Java 11. O CMS (coletor de marca e varredura simultânea) está disponível, mas foi preterido desde Java 9.
A JVM define as configurações padrão de GC para o caso de uso médio. Muitas vezes, esses padrões e outras configurações de GC precisam ser ajustados para uma taxa de transferência ou latência ideal, de acordo com os requisitos do aplicativo. Ajustar corretamente o GC requer um profundo conhecimento do GC, conhecimento que o Grupo de Engenharia Java da Microsoft fornece.
G1GC
O coletor de lixo padrão no Java 11 é o G1GC (coletor de lixo G1). O objetivo do G1GC é encontrar um equilíbrio entre latência e taxa de transferência. O coletor de lixo G1 tenta alcançar alta eficiência cumprindo as metas de tempo de pausa com alta probabilidade. G1GC foi projetado para evitar coleções completas, mas, quando as coleções simultâneas não puderem recuperar memória rápido o suficiente, ocorrerá um GC completo de fallback. O GC completo usa o mesmo número de threads de trabalho paralelos 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 desempenho que usa vários threads para tornar a coleta de lixo mais rápida.
Epsilon [11]
O coletor de lixo Epsilon manipula alocações, mas não recupera nenhuma memória. Quando o heap estiver esgotado, a JVM será encerrada. O Epsilon é útil para serviços de curta duração e para aplicativos que são conhecidos por serem livres de lixo.
Melhorias para contêineres do Docker [12]
Antes do Java 10, as restrições de memória e CPU definidas em um contêiner não eram reconhecidas pela JVM. No Java 8, por exemplo, a JVM define o tamanho máximo do heap para um quarto da memória física do host subjacente. A partir do Java 10, a JVM usa restrições definidas por grupos de controle de contêiner (cgroups) para definir limites de memória e CPU (veja a observação abaixo). Por exemplo, o tamanho máximo de heap padrão é 1/4 do limite de memória do contêiner (por exemplo, 500 MB para -m2G).
As Opções de JVM também foram adicionadas para dar aos usuários do contêiner do Docker controle refinado sobre a quantidade de memória do sistema que será usada para o heap Java.
Esse suporte é habilitado por padrão e só está disponível em plataformas baseadas em Linux.
Observação
A maior parte do trabalho de habilitação do cgroup foi retroportada para o Java 8 a partir do jdk8u191. Melhorias adicionais podem não ser necessariamente retrocedidas para a 8.
Arquivos jar de várias versões [13]
No Java 11, é possível criar um arquivo jar que contenha várias versões específicas da versão java de arquivos de classe. Arquivos .jar de várias versões possibilitam que desenvolvedores de bibliotecas ofereçam suporte a várias versões do Java sem precisar enviar múltiplas versões desses arquivos. Para o consumidor dessas bibliotecas, os arquivos jar com múltiplas versões resolvem o problema de ter que corresponder arquivos jar específicos a destinos de tempo de execução específicos.
Melhorias de desempenho diversas
As seguintes alterações na 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. Essa segmentação fornece melhor controle do volume de memória JVM, reduz o tempo de verificação de métodos compilados, diminui significativamente a fragmentação do cache de código e melhora o desempenho.
JEP 254: Cadeias de Caracteres Compactas [15] – altera a representação interna de uma cadeia de caracteres de dois bytes por char para um ou dois bytes por char, dependendo da codificação char. Como a maioria das cadeias de caracteres contém caracteres ISO-8859-1/Latin-1, essa alteração efetivamente reduz pela metade a quantidade de espaço necessária para armazenar uma cadeia de caracteres.
JEP 310: Compartilhamento de Class-Data de aplicativos [16] – o compartilhamento de Class-Data diminui o tempo de inicialização permitindo que as classes arquivadas sejam mapeadas pela memória em runtime. O Compartilhamento de Dados de Classe de Aplicação estende o compartilhamento de dados de classe, permitindo que as classes de aplicação sejam colocadas no arquivo CDS. Quando várias JVMs compartilham o mesmo arquivo de arquivamento, economiza memória e o tempo geral de resposta do sistema melhora.
JEP 312: Thread-Local Handshakes [17] – possibilita a execução de um callback em threads sem realizar um ponto de segurança global da VM, ajudando assim a VM a alcançar menor latência por meio da redução do número de pontos de segurança globais.
Alocação lenta de threads do compilador [18] – no modo de compilação em camadas, a VM inicia um grande número de threads do compilador. Esse modo é o padrão em sistemas com muitas CPUs. Esses threads são criados independentemente da memória disponível ou do número de solicitações de compilação. Os threads consomem memória mesmo quando estão ociosos (o que é quase o tempo todo), o que leva a um uso ineficiente de recursos. Para resolver esse problema, a implementação foi alterada para iniciar apenas um thread do compilador de cada tipo durante a inicialização. Iniciar threads adicionais e desligar threads não utilizados é tratado dinamicamente.
As alterações a seguir nas bibliotecas principais têm um impacto no desempenho do código novo ou modificado.
JEP 193: Variable Handles [19] – Define um meio padrão para invocar os equivalentes de várias operações java.util.concurrent.atomic e sun.misc.Unsafe em campos de objeto e elementos de matriz, um conjunto padrão de operações de "fence" para controle refinado da ordenação de memória e uma operação padrão de "reachability-fence" para garantir que um objeto referenciado permaneça 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áticos nas interfaces de coleção que criam instâncias de coleção compactas e não passíveis de modificação. Essas instâncias são inerentemente mais eficientes. As APIs criam coleções que são representadas compactamente e não têm uma classe wrapper.
JEP 285: Spin-Wait Hints [21] – fornece uma API que permite ao Java sugerir ao sistema de tempo de execução que está em um loop de espera ativa. Determinadas plataformas de hardware se beneficiam da indicação de software de que um thread está em um estado de espera ativa.
JEP 321: Cliente HTTP (Standard) [22]- Fornece uma nova API de cliente HTTP que implementa HTTP/2 e WebSocket e pode substituir a API httpURLConnection herdada.
Referências
[1] Oracle Corporation, "Java Development Kit 9 Release Notes", (Online). Disponível: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (Acessado em 13 de novembro de 2019).
[2] Oracle Corporation, "Java Development Kit 10 Release Notes", (Online). Disponível: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (Acessado em 13 de novembro de 2019).
[3] Oracle Corporation, "Notas de versão do Java Development Kit 11", (Online). Disponível: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (Acessado em 13 de novembro de 2019).
[4] Oracle Corporation, "Project Jigsaw", 22 de setembro de 2017. (Online). Disponível: http://openjdk.java.net/projects/jigsaw/. (Acessado em 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. (Acessado em 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. (Acessado em 13 de novembro de 2019).
[7] Oracle Corporation, "JEP 158: Unified JVM Logging", 14 de fevereiro de 2019. (Online). Disponível: http://openjdk.java.net/jeps/158. (Acessado em 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. (Acessado em 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. (Acessado em 13 de novembro de 2019).
[10] Oracle Corporation, "JEP 248: Tornar g1 o coletor de lixo padrão", 12 de setembro de 2017. (Online). Disponível: http://openjdk.java.net/jeps/248. (Acessado em 13 de novembro de 2019).
[11] Oracle Corporation, "JEP 318: Epsilon: Um coletor de lixo No-Op", 24 de setembro de 2018. (Online). Disponível: http://openjdk.java.net/jeps/318. (Acessado em 13 de novembro de 2019).
[12] Oracle Corporation, "JDK-8146115: Aprimorar a detecção de contêiner do Docker e o uso de configuração de recursos", 16 de setembro de 2019. (Online). Disponível: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (Acessado em 13 de novembro de 2019).
[13] Oracle Corporation, "JEP 238: Arquivos JAR de várias versões", 22 de junho de 2017. (Online). Disponível: http://openjdk.java.net/jeps/238. (Acessado em 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. (Acessado em 13 de novembro de 2019).
[15] Oracle Corporation, "JEP 254: Compact Strings", 18 de maio de 2019. (Online). Disponível: http://openjdk.java.net/jeps/254. (Acessado em 13 de novembro de 2019).
[16] Oracle Corporation, "JEP 310: Application Class-Data Sharing", 17 de agosto de 2018. (Online). Disponível: https://openjdk.java.net/jeps/310. (Acessado em 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. (Acessado em 13 de novembro de 2019).
[18] Oracle Corporation, "JDK-8198756: Alocação lenta de threads do compilador", 29 de outubro de 2018. (Online). Disponível: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (Acessado em 13 de novembro de 2019).
[19] Oracle Corporation, "JEP 193: Manipuladores de Variáveis," 17 de agosto de 2017. (Online). Disponível: https://openjdk.java.net/jeps/193. (Acessado em 13 de novembro de 2019).
[20] Oracle Corporation, "JEP 269: Métodos de Fábrica Convenientes para Coleções", 26 de junho de 2017. (Online). Disponível: https://openjdk.java.net/jeps/269. (Acessado em 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. (Acessado em 13 de novembro de 2019).
[22] Oracle Corporation, "JEP 321: Cliente HTTP (Standard)", 27 de setembro de 2018. (Online). Disponível: https://openjdk.java.net/jeps/321. (Acessado em 13 de novembro de 2019).