De que se trata o artigo:

Exploramos várias alternativas às JVMs comuns, como o Sun JDK ou IBM JDK, como plataforma de execução de aplicações Java. Estas alternativas incluem compiladores estáticos, implementações livres de Java, e até mesmo a execução de código java em VMs .NET.


Para que serve:

Praticamente todas as aplicações Java são executadas numa JVM, o que é natural pois a JVM é o ambiente de execução oficial e “natural” da linguagem Java e das suas APIs, frameworks, containers, etc. Muitos desenvolvedores podem nem saber da existência de outra maneira, que não seja uma JVM, de rodar código Java. Mas existem outras maneiras, e para algumas aplicações pelo menos, estas alternativas podem oferecer vantagens interessantes.


Em que situação o tema é útil:

Aplicações GUI desktop (Swing ou SWT) podem ter vantagens de tempo de carregamento e consumo de memória, especialmente com compiladores estáticos;

Compiladores estáticos também permitem distribuir aplicações sem revelar seus fontes, nem mesmo indiretamente através de bytecode Java, que é relativamente fácil de descompilar;

Em alguns projetos e ambientes heterogêneos, o convívio, integração e mesmo reuso de código entre sistemas Java e .NET pode ser uma vantagem, havendo valor em qualquer tecnologia que reduza a necessidade de reimplementar código Java em C# ou vice-versa.

Aproveitamos também para realizar alguns testes de desempenho, que são usados como guia para explicações de características de implementação de cada plataforma de execução; e para explorar alguns aspectos do consumo de memória pelas aplicações Java.

Este artigo explora opções alternativas de compilação e distribuição/instalação de aplicações Java. Todo desenvolvedor Java está acostumado com a opção “oficial” – compilar para bytecode com o javac, gerar arquivos como JAR/WAR/EAR, fazer deployment em containers Java EE ou talvez com JNLP para Applets e WebStart. Mas existem opções – já pensou em gerar um arquivo executável (como um .EXE no Windows) contendo uma aplicação Java completa, que não exige um JRE? Ou então, compilar uma aplicação Java de tal forma a executar na plataforma .NET? Neste artigo vamos explorar estas possibilidades, inclusive variações da opção mais tradicional, como o OpenJDK.

O leitor veterano desta coluna poderá lembrar do artigo “JVMs Alternativas”, Edição 24. Mas além da atualização dos últimos anos, a abordagem aqui é bastante diferente, e cobre em maior profundidade os poucos itens em comum.


Motivação e Histórico

Quando a plataforma Java foi lançada, se notabilizava por uma característica então bem pouco comum: o uso de uma Máquina Virtual (VM), arquitetura de execução que trazia vantagens como a distribuição de código em formato portável (bytecode) e com garantias de segurança e estabilidade (o que é atualmente chamado de “código gerenciado”). Existiam linguagens bem mais antigas que usavam VMs, mas Java inovou em alguns aspectos (especialmente no foco em código seguro) e teve o mérito de realmente popularizar o conceito de VM.

Muito do sucesso do Java deve-se à opção pela VM. Ainda assim, desde o começo, uma das perguntas mais comuns de iniciantes era: Dá para gerar um “programa compilado”? E não adianta apontar para o compilador JIT da JVM; para alguns, a necessidade de gerar um arquivo executável nativo, como um .EXE, continua sendo importante por outras razões – que podemos listar:

• Facilidade de distribuição/instalação de aplicações;

• Maior grau de controle/administração das aplicações instaladas;

• Vantagens de desempenho.

Algumas destas vantagens eram grandes nos primórdios da plataforma Java, o que abriu as portas para um competitivo mercado de “compiladores estáticos” para Java (neste artigo vamos chamá-los apenas de compiladores, para simplificar). Eu cheguei a testar e avaliar a maioria deles (ver quadro “Histórico: A primeira geração de Compiladores Java”).

Histórico: A primeira geração de Compiladores Java

Os leitores veteranos desta coluna terão flashbacks ao ouvirem nomes como TowerJ, BulletTrain, JOVE, Supercede, GCJ e JET; os mais iniciantes, porém, nem saberão do que se trata. Isso por que quase toda a primeira geração de produtos desse tipo – compiladores estáticos para Java – acabou não sobrevivendo. Isso aconteceu em parte por que a linguagem Java e seus frameworks foram projetados para serem executados por uma VM; o modelo de compilação estática, que serve muito bem a linguagens como C e C++, nem sempre é tão bom para Java. Mas é interessante examinar os motivos pelo quais estes produtos surgiram, e os motivos pelos quais a maioria não sobreviveu.

Preço: Quase todos eram produtos comerciais, em geral bastante caros. Alguns tinham preços na ordem das dezenas de milhares de dólares; outros tinham um modelo de vendas bem estranho (você não podia comprar o compilador – precisava submeter seu bytecode à empresa, que devolvia o executável compilado);

Visão de curto prazo: Os produtos exploravam fraquezas das primeiras versões do JDK. Por exemplo, o TowerJ devia muito do seu sucesso às suas bibliotecas otimizadas para I/O e threads, escalando para um número maior de conexões. O BulletTrain era bem melhor em GC e nas bibliotecas numéricas/matemáticas. O JOVE era melhor na otimização de código OO. Tão logo as JVMs (em especial a partir do JDK 1.2) recuperaram o atraso, oferecendo desempenho similar ou até melhor, e ainda por cima de graça, aqueles produtos deixaram de ser necessários;

A bolha: O plano de negócio das empresas que investiram nestes produtos fazia mais sentido nos anos dourados do “dot-com”. Quando a bolha estourou e ninguém mais tinha dinheiro para produtos caros com vantagens modestas, a festa terminou. (Alguns dos desenvolvedores destes produtos acabaram arranjando emprego na Sun...);

A revolução do HotSpot: Estes planos também se fiavam que a arquitetura de VM com compilador JIT nunca teria excelente desempenho. Era o que todo mundo pensava, pois era a realidade antes do Java2 e do HotSpot (e também do IBM JDK, que no mesmo período também estreou a VM “J9”). Quem apostava na tecnologia de compilação tradicional, a la C/C++, não enxergou a locomotiva dos compiladores JIT modernos, com otimizações dinâmicas e especulativas, surgindo no fim do túnel;

Código dinâmico: Também aconteceu a rápida ascensão da plataforma J2EE, que dependia muito mais de capacidades de execução dinâmica (desde reflection e RMI até a criação e alteração de classes em tempo de execução) que os compiladores estáticos não tinham. Com o tempo estes produtos desenvolveram uma resposta para isso – um runtime híbrido, capaz de combinar compilação estática para o código conhecido em tempo de compilação, com compilação JIT para código mais dinâmico – mas então, já era tarde para recuperar o terreno perdido.

Assim foi que, após alguns anos de crescimento meteórico, a maioria dos vendedores fechou as portas ainda mais rapidamente. Os únicos sobreviventes foram o GCJ (projeto open source – portanto com custo muito baixo de manutenção), e o JET (produto de uma empresa russa, com custos mais enxutos). Mas esta sobrevivência foi valiosa, pois como vemos neste artigo, a opção de compilação estática continua tendo algumas vantagens, ainda que mais limitadas do que nos “bons tempos” em que algum compilador estático podia deixar uma aplicação 10 vezes mais eficiente do que com o jurássico Sun JDK 1.1.

Como curiosidade histórica (e para diversão do leitor), desenterrei dos meus folders de 1999 – época em que testei seriamente praticamente todas as implementações de Java, para escrever a então-famosa série de artigos “Java Performance Report” – um interessante trecho de e-mail, que traduzo abaixo pois ilustra alguns pontos acima...:

Só por que nós não temos os dólares de marketing da Sun para promover vaporware como o HotSpot, não pense que nós não sabemos o que estamos fazendo. De fato, o oposto é verdadeiro. Quando percebi que a Sun iria apostar tudo na ideia de compilação dinâmica, soubemos que iríamos ficar ricos e famosos. (Você pode chamar um porco de puro-sangue o quanto quiser, mas isso não significa que você vá ganhar a corrida.)

Não identifico o autor precisamente por elegância; só digo que esta foi uma das empresas cujo produto desapareceu após o “vaporware” do HotSpot provar que, realmente, era um “puro-sangue”. ;-) Os artigos JPR foram publicados em javalobby.org mas foram retirados há anos, e não faço questão de recolocá-los em algum outro site, é muita velharia. Mas o leitor curioso pode ver um resumo dessa história (além de outros assuntos mais além) em The Tale of Java Performance, que escrevi para o Journal of Object Technology: http://www.jot.fm/issues/issue_2003_09/column3/.

As vantagens dos compiladores diminuíram – mas não desapareceram totalmente. A velocidade de execução de aplicações foi superada pelas JVMs, mas o tempo de carregamento e consumo de memória continuam no lado dos executáveis nativos. A facilidade de instalação foi melhorada com o Java WebStart, mas há quem prefira instaladores convencionais. Quanto à administração, um executável nativo independente não fica sujeito a problemas com atualizações do JRE – problemas que são quase sempre bugs da aplicação, mas explique isso para a equipe de TI responsável por uma aplicação corporativa! E no outro lado da moeda, os compiladores estáticos ganharam inteligência para executar aplicações dinâmicas e até mesmo containers J2EE (embora o resultado possa ter alguns custos em facilidade de administração e desempenho).

Em paralelo, a plataforma Java logo ganhou concorrência da Microsoft, com o lançamento da plataforma .NET – inicialmente muito parecida com Java, especialmente nas arquiteturas de VM e na versão inicial da sua linguagem primária (C#). Um fato interessante da .NET é que esta plataforma suporta a compilação AOT (ahead-of-time) – algo parecido com a compilação JIT, mas feita no momento da instalação da aplicação, e não a cada execução. (Algumas JVMs também suportam esta opção, especialmente o IBM JDK, e o projeto Jigsaw do JDK 7 também tem o potencial de permitir compilação AOT, embora talvez isso não seja entregue já no JDK 7.0-FCS.) Outro fato menos conhecido da .NET é que o Mono, uma implementação open source da .NET, inclui a extensão IKVM, que habilita suporte total não só à linguagem Java, mas também a todas as APIs do Java SE. Com a IKVM, pode-se também realizar compilação AOT de programas Java, isso sem falar na opção às vezes útil de compilação cruzada Java/.NET.

...
Quer ler esse conteúdo completo? Tenha acesso completo