terça-feira, 12 de agosto de 2008

Tagged under: , ,

Resolvendo problemas de performance (parte 4 - final)

Finalizando essa série de posts (parte 1, parte 2 e parte 3), vamos conhecer a geração que até então tínhamos deixado de lado: a geração permanente (permanent generation).

Permanent Space

O Heap (espaços eden, survivor e tenured juntos ) é o local onde residem as instâncias das classes (objetos). Antes da JVM criar uma instância de uma classe no eden space, as informações sobre a classe em si são carregadas para a memória - um processo análogo ao dos meta-dados de um banco de dados. O espaço da memória que a JVM usa para armazenar esses bytecodes do arquivo .class é o espaço permanente (permanent space). A figura abaixo mostra a relação entre o espaço permanente e o heap.


O ideal é que o espaço permanente seja tão grande quanto a quantidade de classes que a nossa aplicação carrega; afinal, ler a classe da memória é obviamente mais rápido do que lê-las do disco. Os coletores serial e paralelo limpam essa área quando assim o desejam (baseado em estatísticas internas). Para garantir que as classes não sejam removidas do espaço permanente, existe o parâmetro -noclassgc. Esse parâmetro define que a JVM não fará coleta de lixo no espaço permanente e, consequentemente, não removerá os bytecodes das classes de lá.

Esse ajuste seria inteligente se não nos trouxesse uma preocupação: o que acontecerá quando o espaço permanente estiver cheio e precisar carregar uma nova classe? Pelo que já aprendemos, a JVM examinará o espaço permanente e verá que precisa de mais memória, realizando uma coleção maior. O GC limpará o heap mas não fará nada no espaço permanente - o que terá sido um esforço inútil. A JVM examinará novamente o espaço permanente, verá que está cheio e repetirá o processo novamente, e novamente, e novamente. Após um tempo (definido na JVM), uma exceção OutOfMemoryError será lançada e a aplicação encerrará. A figura abaixo ilustra esse processo quando esse parâmetro está ativado.


Esse problema acontece principalmente em aplicações web que carregam milhares de JSP's, e que são traduzidas em código Java, compiladas para bytecode e colocadas no espaço permanente antes de criar uma instância no heap.

A recomendação é dimensionar esse espaço de memória para que caibam todas as classes usadas pela sua aplicação e ter uma folga para classes que serão adicionadas no futuro. Os parâmetros para dimensionar o permanent space são -XX:PermSize e -XX:MaxPermSize, que respectivamente definem o tamanho inicial e o tamanho máximo do espaço. Exemplo:
C:/JDK_HOME/bin/java -XX:PermSize=64m -XX:MaxPermSize=256m -jar MyApp.jar

Coletor concorrente no espaço permanente

Quando ativamos o coletor concorrente (concurrent collector) para a nossa aplicação, temos que nos preocupar com uma característica intrínseca desse coletor: ele nunca limpa o espaço permanente. Contudo, você pode mudar esse comportamento com os parâmetros -XX:CMSClassUnloadingEnabled e -XX:CMSPermGenSweepingEnabled.

A coleta de lixo na área permanente aumentará o tempo de pausa e pode encobrir problemas em bibliotecas e API's usadas pela nossa aplicação. O ideal é que não ative esse parâmetros a não ser que tenha uma forte razão para isso. Limite-se a dimensionar o espaço permanente, aumentando o seu tamanho máximo, e monitore a aplicação para verificar o comportamento da memória.

É o fim!

Espero ter ajudado a conhecer o mundo do gerenciamento de memória do Java e, quem sabe, ajudar a resolver problemas de performance em sua aplicação.

Para saber mais sobre os assuntos que foram tratados aqui, sugiro que visitem os seguintes links:
Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
Gerenciamento de memória em Java - Helder da Rocha - parte 1
Gerenciamento de memória em Java - Helder da Rocha - parte 2
Gerenciamento de memória em Java - Helder da Rocha - parte 3

Até a próxima!

3 comentários:

Carlos Carneiro disse...

Muito bom, parabéns!!

Rafael Braga disse...

Very Nice, Congratulations!! :-)

Raul Abreu Leite disse...

Excelente série de artigos, foi de grande ajuda. Abraços!