ns = "urn:schemas-microsoft-com:office:office" />

De onde veio, para onde vai

O estado da arte em técnicas usadas em JVMs, para execução eficiente de aplicações Java

Desempenho é uma dessas coisas que sempre nos falta. Quando o software é rápido o bastante, sempre poderia ser ainda mais rápido para exigir menos hardware. Melhor ainda, deveria ser possível escrever um software de alto desempenho sem precisar de um time inteiro de “gurus” – pessoas são mais caras que equipamentos.

No caso do Java, desempenho já fez muita falta, especialmente na infância da plataforma (JDK 1.0.x). O progresso feito até hoje foi enorme, mas há muita desinformação sobre o desempenho do Java. Neste artigo, vamos começar com um histórico do progresso nesta área, e discutir questões principais de desempenho da plataforma, concentrando-se na tecnologia de runtime (especialmente a Java Virtual Machine – JVM).

Interpretação

O Java usa um formato de código executável portável, o bytecode, que não é reconhecido por CPUs tradicionais como x86, SPARC ou PowerPC. As primeiras JVMs eram puramente interpretadas. O interpretador é um programa conceitualmente simples. Para cada instrução bytecode (por exemplo getfield #3), temos:

1.    Leitura: Obtém o bytecode a partir do ponteiro para a próxima instrução (que é incrementado).

2.    Decodificação: Invoca uma rotina específica a partir do tipo do bytecode; ou seja, um grande switch pulando para o código que trata getfield. Também extrai parâmetros, no caso o #3.

3.    Execução: Realiza a operação; no exemplo, “getfield #3” significa “extraia o valor no topo da pilha, que é referência para um objeto; obtenha seu terceiro atributo e o coloque no topo da pilha”.

Parece simples, mas é muito mais lento que código nativo. Um programa nativo poderia realizar a operação equivalente com uma só instrução (em x86: MOV EAX,[EAX+16]); sem os custos de leitura e decodificação, sem a necessidade de manipular todos os valores usando uma pilha (no bytecode não há “registradores virtuais” pois isso dificultaria a portabilidade), e com o benefício de muitas otimizações.

As JVMs atuais têm interpretadores excelentes, escritos em assembly e capazes de algumas otimizações, mas ainda assim a interpretação é pelo menos dez vezes mais lenta que o código nativo equivalente. Mas nem tudo é ruim no mundo da interpretação. O consumo de memória é um ponto positivo: código bytecode é compacto e fácil de compartilhar entre vários programas rodando na mesma máquina. Para aplicações que fazem uso intenso de serviços do sistema operacional (APIs gráficas, comunicação, entrada e saída), o desempenho do bytecode tem pouco peso. Na plataforma J2ME, por exemplo, ainda é popular o uso de JVMs puramente interpretadas, cujo custo/benefício é positivo para as limitações de hardware dos dispositivos.

...

Quer ler esse conteúdo completo? Tenha acesso completo