Esse artigo faz parte da revista Java Magazine edição 31. Clique aqui para ler todos os artigos desta edição

Atenção: por essa edição ser muito antiga não há arquivo PDF para download.Os artigos dessa edição estão disponíveis somente através do formato HTML. 

Novas Fronteiras do Java

Evolução e perspectivas da linguagem e plataforma

 

Uma análise dos rumos da evolução futura da linguagem e plataforma Java, e uma exploração de pesquisas em otimizações promissoras para JVMs

 

Osvaldo Pinali Doederlein

 

Na edição anterior (“Performance Aplicada”), exploramos o estado da arte das máquinas virtuais Java, mostrando como funcionam algumas otimizações avançadas das JVMs da Sun e de outras empresas, inclusive algumas já em desenvolvimento para o Mustang (Java SE 6).

Olhando mais além, ainda podemos esperar muitas melhorias importantes? Ou será que as JVMs atuais já implementaram todas as otimizações de maior impacto, e só teremos avanços incrementais cada vez menores?

Além disso, quanto à linguagem, estamos satisfeitos com as novidades do Java 5 ou precisamos de novas melhorias de sintaxe?

Para responder a essas perguntas, vamos apresentar diversas idéias que atualmente estão nos “laboratórios” e que poderão estar disponíveis na plataforma Java SE daqui a algum tempo. Também vamos analisar o panorama da pesquisa que está definindo novos rumos para a tecnologia Java.

Como veremos, boa parte das novas tecnologias não é desenvolvida inicialmente pelos implementadores do Java, como a Sun e a IBM, e sim no meio acadêmico. Até as empresas mais inovadoras costumam focar investimentos em técnicas que já passaram por um estágio de amadurecimento, provando que são viáveis. É nas universidades que acontecem os estudos mais arriscados, apresentando conceitos totalmente novos, e que talvez proporcionem a próxima revolução em linguagens e compiladores. A maioria das futuras tecnologias de impacto não são segredos comerciais: são material de acesso público, disponíveis para download gratuito na internet1.

Se por um lado podemos melhorar a implementação de linguagens existentes de forma transparente para o desenvolvedor, as linguagens em si também estão em contínua evolução e competição. Acompanhando o recente lançamento do .Net 2.0 e C# 2.0, vamos examinar a disputa Java versus Microsoft e suas direções futuras, focando na evolução do Java e outras linguagens para execução sobre JVMs como o Groovy.

 

Utilizamos aqui alguns termos pouco usuais em publicações sobre programação, especialmente conceitos de arquitetura de hardware que são essenciais para entender pesquisas sobre implementações de JVMs. Esses termos, identificados com marcadores “D, são explicados no quadro “Conceitos”

 

Java: a plataforma da pesquisa

O sucesso acadêmico do Java e a Jikes RVM

Conhecemos bem a popularidade do Java no desenvolvimento de aplicações, mas é menos difundido o seu sucesso para pesquisa. Este sucesso não é difícil entender. Linguagens para pesquisa devem ser idealmente abertas e multiplataforma, facilitando a divulgação de trabalhos na comunidade acadêmica global. Também devem ser de alto nível, poderosas e dinâmicas, facilitando a codificação de algoritmos complexos. Linguagens com funcionalidades como reflection e execução interpretada tornam mais fáceis técnicas de meta-programação, as quais facilitam especialmente pesquisas em linguagens e compiladores. Também é muito útil que a linguagem seja "popular" (de sucesso comercial), pois isso aumenta a oferta de ferramentas e de literatura, e expande a comunidade. Além de trazer mais facilidade na transição de pesquisas para produtos. Finalmente, bom desempenho nunca faz mal!

Tradicionalmente, a linguagem C ocupava boa parte do espaço de linguagens de pesquisa, por ser popular, aberta, multiplataforma (ainda que com reservas) e eficiente. Mas como C é uma linguagem de baixo nível e nada dinâmica, muitos preferiam as linguagens "OO-puras" como Smalltalk e as funcionais como Lisp, Scheme e ML; mas estas tinham desvantagens de portabilidade e desempenho - e pouco sucesso comercial2.

A linguagem Java venceu essas barreiras, reunindo uma massa crítica de qualidades desejáveis em linguagens de pesquisa num só pacote. Pode não ser  uma linguagem tão boa quanto todas essas outras em todos os requisitos mencionados, mas tem um equilíbrio excelente, sendo pelo menos aceitável em todos.

 

A Jiles RVM

Nos últimos anos, a tecnologia Java também tem se beneficiado de uma ferramenta ímpar - a Jikes Research VM (RVM), que já mencionamos no artigo "JVMs Alternativas" na Edição 24. Criada pela IBM e depois transformada num projeto open source, a RVM é implementa da totalmente em Java, sendo capaz de executar a si mesma mediante técnicas de bootstrappingD.

A RVM torna a pesquisa de novas técnicas de implementação de JVMs bem mais fácil do que com VMs implementadas numa outra linguagem. Esse tipo de plataforma é essencial para pesquisas avançadas em linguagens e compiladores. Se você visitar os índices de palestras técnicas das principais conferências de pesquisa de linguagens, encabeçadas pela ECOOP e pela OOPSLA3, verá que o Java é de longe a linguagem mais utilizada nos estudos apresentados. As pesquisas de implementação e otimização de VMs, em especial, agora são quase todas feitas com a Jikes RVM. Um benefício disso é que a comunidade acadêmica acaba fazendo pesquisa "de graça" para a indústria de Java.

Embora concorrentes semelhantes, como .Net/C#, também possam se beneficiar dessas pesquisas, na prática é muito mais simples portar uma nova otimização criada na Jikes RVM para uma JVM de produção como a da Sun (HotSpot) ou da IBM (J9), do que adaptá-la para outras plataformas e linguagens.

 

A Jikes RVM é totalmente compatível com a especificação da máquina virtual Java, e também utiliza as APIs padrão da plataforma Java SE fornecidas pelo projeto GNU Classpath.

 

A RVM tem a reputação de ser de alto desempenho e implementar as mesmas otimizações avançadas que JVMs de produção. Para conferir, testei a versão 2.4.1. A instalação exige baixar os fontes e compilá-los, sendo que há apenas suporte a Linux (em PowerPC ou Intel x864). Fiz os testes com o Ubuntu Linux 5.1. A compilação é simples, bastando seguir o manual à risca: é preciso uma JVM padrão J2SE 1.4.x, pois a RVM ainda não funciona com releases do Java 5.

Tive sucesso com o JDK 1.4.2_10 da Sun, e a documentação informa que a RVM rodará também sobre a JVM livre Kaffe. Comparando o desempenho da RVM (na configuração "production") ao do Sun HotSpot 1.4.2_10 usando o benchmark SciMark2, a RVM um escore de 320 num Pentium-IV 2.4 GHz - um resultado intermediário entre o HotSpot Client (224) e o HotSpot Server (549).

Entretanto, a RVM teve um consumo bem maior de memória: 45 Mb contra 10 Mb do HotSpot. Isso é em parte fruto da sua arquitetura, sendo implementada de forma extremamente modular, escrita num estilo de alto nível e com flexibilidades e opções não existentes em VMs de produção. Por exemplo, existem opções que permitem gravar num arquivo as decisões de otimização da JVM durante toda a execução de um programa. Depois, pode-se carregar este arquivo para garantir que a nova execução será exatamente igual, com o código sendo compilado da mesma maneira - o que torna a análise de benchmarks mais precisa. Normalmente isso não seria garantido, pois o comportamento do compilador JIT (de qualquer JVM moderna) não é totalmente determinístico5.

Também há opções que violam especificações do Java, mas são importantes para pesquisa. Por exemplo -X:opt:no_checkcast, no_null_check, no_bounds_check, no_synchro, e outras, permitem eliminar totalmente as verificações de operações de conversão, ponteiros, índices de arrays e até mesmo de sincronização de monitores. A idéia é permitir a avaliação do impacto que cada verificação tem num benchmark - e validar otimizações do compilador que procuram reduzir o custo das verificações.

Para testar, executei novamente o SciMark2 com todas as opções -X:opt:no_* (exceto no_null_check que causava uma pane da JVM). O resultado foi o aumento do escore de 320 para 419. E não deixa de ser divertido usar uma JVM que tem opções como frequency-strategy=dumb e spill_ cost_estimate=brainDead!

 

Novos Avanços em JVMS

Inovações e Pespectivas em Garbage Collection e Concorrência

Vamos explorar alguns dos avanços mais interessantes que têm aparecido em papers e estudos acadêmicos. 5elecionamos dois temas principais: Garbage Collection e Concorrência. Também existem novidades do mesmo porte "no forno" em outras áreas, como compilação JIT (que vimos com detalhe na edição anterior: "Performance Aplicada") e o suporte a técnicas de programação alternativas, como a programação orientada a aspectos (AOP), mas reduzimos o escopo para oferecer uma visão mais aprofundada.

 

Garbage Collection: limpeza otimizada

Um assunto que nunca está esgotado é o de novas otimizações de Garbage Collection (GC). Temos mais avanços nesta área porque ainda há cenários onde o desempenho de sistemas de memória automática pode melhorar.

 

GC versus paginação

Um dos maiores problemas da plataforma Java, ou de qualquer sistema com GC, é a briga do Garbage Collector ("coletor de lixo") com a memória virtual do sistema operacional. Se um computador tem 100 Mb de memória física livre e é necessário rodar uma aplicação que consome 150 Mb, o SO precisará, claro, jogar 50 Mb para o arquivo de paginação. Mesmo com isso, o desempenho pode ser bom, se as páginas de memóriaD de uso mais freqüente forem mantidas na RAM, e as menos utilizadas ficarem no disco.

Quando o coletor de lixo entra em ação, varrendo o heap para descobrir quais objetos são lixo, ele acaba visitando páginas de memória que foram descartadas. Isso é ineficiente, primeiro porque força a leitura destas páginas do arquivo de paginação; segundo porque esta leitura pode forçar o descarte de páginas do working set. (É chamado de working set o conjunto de páginas de uso freqüente, que a aplicação precisa ter na RAM para executar com bom desempenho, e com pouca ou nenhuma paginação.)

O resultado é que a coleta de lixo demora muito devido à paginação, e também deixa a aplicação mais lenta por algum tempo, até que as páginas do working set que foram descartadas sejam lidas novamente. Este problema é grave e só não é mais visível porque afeta mais a coletas full-GCD, raras em coletores generacionaisD modernos.

O paper "Garbage Collection Without Paging"6 propõe uma solução para esse problema, através de um novo coletor de lixo chamado bookmarking collector, que trabalha em cooperação com o sistema operacional. Quando o SO quer descartar algumas páginas do heap de um processo Java, o coletor é notificado e tem a chance de selecionar quais páginas serão descartadas, tendo condições de fazer escolhas melhores que o SO. Pode-se evitar o descarte de páginas da geração jovemD (coletadas com mais freqüência), ou escolher o descarte de páginas livres.

Além disso, o coletor usa as notificações para criar os "bookmarks": indicações das páginas na RAM que possuem objetos com referências para páginas no disco. Ao fazer coletas, o coletor usa os bookmarks para evitar visitas a páginas que estão no disco, o que só permite coletas parciais e talvez aumente a freqüência das coletas, mas evita o custo muito maior de fazer I/O de swap.

Os resultados de desempenho do coletor com bookmarking são impressionantes. Em testes com muita pressão de memória (ex.: aplicações com working set maior que a RAM disponível), ele produz pausas de coleta até mais de 200 vezes menores que um coletor de referência de alta performance - e pode produzir um desempenho global da aplicação até 40 vezes maior.

A maior dificuldade é que o coletor com bookmarking exige ajuda do SO. Os autores precisaram criar uma nova função do kernel do Linux (vm_relinquish()) para fazer as notificações. É possível que esta melhoria venha a fazer parte de versões futuras do kernel, pois seria benéfica para outros softwares com necessidades especiais de gerenciamento de memória, como SGBDs.

 

GC versus caches

Mesmo com memória abundante, não havendo problemas de paginação, tem-se constatado que o custo da coleta de lixo é maior do que se pensava. Estudos mais antigos contavam somente o tempo gasto pela execução de coletas e por instruções de barreira de memóriaD que os coletores generacionais ou concorrentes precisam inserir na aplicação. Mas em arquiteturas de hardware modernas existem outros custos, que são bem mais difíceis de medir.

...

Quer ler esse conteúdo completo? Tenha acesso completo