De que se trata o artigo:
O artigo visa o gerenciamento de memória utilizado pela Java Virtual Machine e as formas existentes de otimização das JVMs instanciadas na memória de acordo com a característica das aplicações e do ambiente (Hardware + Sistema Operacional) em que a aplicação se encontra
Para que serve:
O artigo apresenta de uma forma bem objetiva como é possível otimizar os recursos computacionais, mais especificamente memória volátil, utilizados pela Java Virtual Machine (JVM) na interpretação dos Byte Codes, e apresentar as opções disponibilizadas pela Sun para inicializarmos uma aplicação Java.
Em que situação o tema é útil:
O artigo é útil para intervenções pró-ativas ou corretivas no processo de consumo de memória volátil pelas aplicações e otimização das regiões de memória utilizadas pela Java Virtual Machine.
Nós, desenvolvedores, muitas vezes focamos nosso trabalho na implementação de soluções para o software que está sendo desenvolvido, e acabamos não nos preocupando com o desempenho da aplicação no ambiente de produção. É muito difícil estimar o quanto nossa aplicação será demandada por requisições e o quanto dessas requisições irão impactar no desempenho da aplicação e do consumo dos recursos de hardware, mais especificamente memória volátil.
Para podermos ter esta percepção, por mais que planejemos, só conseguimos ter estes parâmetros de demanda real quando a aplicação entra
É neste contexto que se torna importante e um diferencial interessante ao desenvolvedor Java conhecer as possibilidades de otimização da Java Virtual Machine (JVM – ver Nota DevMan 1) no processo de gerenciamento de memória e a forma como a JVM utiliza este recurso de hardware. Na grande maioria das vezes, estas opções de otimização acabam passando despercebidas, onde só iremos dar a devida importância a esta otimização quando a situação já não está muito confortável.
Nota DevMan 1. Java Virtual Machine – JVM – (Máquina Virtual Java)
Uma Máquina Virtual Java (Java Virtual Machine – JVM) é um conjunto de programas de software e estrutura de dados que usa um modelo de máquina virtual para a execução de outros programas computacionais e scripts. O modelo usado por uma JVM aceita uma forma de linguagem intermediária de computador comumente referenciada como bytecode Java. Esta linguagem representa conceitualmente o conjunto de instruções de uma arquitetura orientada a pilha. Em 2006 foi estimado que existe um número em torno de 4 bilhões de dispositivos de JVM habilitados em todo o mundo.
As Máquinas Virtuais Java operam sobre bytecode Java, que é normalmente, mas não necessariamente, gerado a partir de código Java; uma JVM pode também ser usada para implementar linguagens de programação diferentes de Java. Por exemplo, código fonte em Ada pode ser compilado para bytecode Java, que poderá então ser executado por uma JVM.
A JVM é um componente crucial da Plataforma Java. Visto que JVMs estão disponíveis para muitas plataformas de hardware e software, Java pode ser tanto middleware e uma plataforma – daí a marca: escreve uma vez, roda em qualquer lugar (write once, run anywhere). O uso do mesmo bytecode para todas as plataformas permite que a linguagem seja descrita como “compila uma vez, roda em qualquer lugar" (“compile once, run anywhere”).
A JVM é distribuída junto com um conjunto de bibliotecas de classes padrões que implementam a API (Application Programming Interface) Java. A máquina virtual e a API têm que ser consistentes entre si e são, portanto, agrupadas em conjunto como o famoso Java Runtime Environment - JRE.
A arquitetura de JVM permite um controle muito fino sobre as ações liberadas para o código que está rodando na VM. Isso permite a execução de código confiável de fontes remotas, um modelo usado pelos applets. Os applets rodam dentro de uma VM incorporada ao browser do usuário, executando código baixado de um servidor HTTP remoto. O código remoto roda em uma sandbox, que protege o usuário de códigos maliciosos. O autor do applet pode aplicar um certificado para assinar digitalmente o applet como "seguro", dando a ele permissão de sair do sandbox e acessar livremente a máquina onde está rodando.
Os programas que rodam sobre uma JVM devem ser compilados em um formato binário portável padronizado, que tipicamente vem na forma de arquivos .class. Um programa pode ser composto de muitas classes em diferentes arquivos. Para facilitar a distribuição de programas maiores, os diversos arquivos de classes podem ser empacotados juntos em um arquivo .jar (acrônimo para Java ARchive).
Entender o gerenciamento de memória e as divisões feitas neste espaço reservado pela JVM é um conhecimento interessante, pois é permitido intervir na otimização do ambiente, e por que não dizer da aplicação, de uma forma pró-ativa e não apenas corretiva.
No decorrer deste artigo, serão apresentadas as possibilidades de otimização, as formas de otimização de cada sub-região feita pela JVM e a melhor forma de escolher os parâmetros corretos no processo de otimização da JVM.
Para demonstrar o estudo, foi utilizado o pacote JDK 1.5.0_14 juntamente com o Web Server Apache Tomcat na sua versão 6.0.18. O ambiente em que foi hospedado o Web Server é um equipamento Sun Netra 105, com processador Ultra Sparc 440mhz de 64bits com 512 de RAM. A aplicação utilizada para administração do Apache Tomcat e apresentação das informações da JVM pelo Tomcat foi a Lambda Probe na sua versão 1.7b.
O exemplo utilizado no artigo é bem simples, onde o intuito é demonstrar como podemos utilizar os recursos disponibilizados pela JVM para otimizar o recurso de memória volátil do hardware. No decorrer do artigo será descrito o exemplo utilizado e das possibilidades de otimização do gerenciamento de memória.
Divisões de memória pela JVM
A linguagem Java utiliza duas formas de alocação de recursos de memória: alocação dinâmica e linear.
A alocação dinâmica visa à livre administração do espaço de memória volátil pela JVM. A ordem de alocação e liberação dos recursos é aleatória, e não existe um procedimento formal.
A alocação linear reserva o espaço de memória volátil em forma de pilha. A alocação e liberação de recursos de memória volátil são feitas seguindo os conceitos de Pilha (LIFO – Last in, First out – o último que entra é o primeiro que sai).
A linguagem Java utiliza a alocação dinâmica e a alocação linear para regiões diferentes de memória. Estas regiões, basicamente, são o ...