BT

O Java 8 resolverá o ‘PermGen OutOfMemoryError’?

por Fabian Lange , traduzido por Rafael Alves em 22 Mar 2013 |

Como parte do projeto em andamento para mesclar o código do HotSpot e JRockit, a Oracle anunciou que irá remover a PermGen da JVM HotSpot no Java 8, e muitas pessoas têm interpretado esse anúncio como indicativo de que todos os erros de PermGen irão desaparecer. Como impacto da remoção da PermGen pode agora ser verificado com os builds do Java 8 Early Access, pode-se descobrir se todos os problemas foram realmente resolvidos.

Em 2006, Jon Masamitsu, desenvolvedor da JVM na Oracle, explicou em seu blog o própósito do PermGen (geração permanente): guardar informações sobre as classes Java, como bytecode, nomes e informações do compilador JIT. Essas informações são armazenadas em um espaço reservado porque a maioria é estática, e a operação do coletor de lixo pode ser muito mais otimizada mantendo a geração permanente separada.

Muitos desenvolvedores já se depararam com o erro "java.lang.OutOfMemoryError: PermGen space" em seus sistemas, o que é geralmente causado pelo vazamento de memória em classloaders e à criação de novos classloaders. Esse vazamento geralmente acontece durante o hot deploy de código, por isso a ocorrência do erro é mais frequente em ambiente de desenvolvimento do que de produção. Quando ocorre em produção, os desenvolvedores podem analisar o despejo de heap gerado com uma ferramenta como o Eclipse Memory Analyzer Toolkit, para procurar por classloaders que não deveriam estar mais presentes, mas que por algum motivo ainda estão.

A coleção permanente é coletada, a menos que uma configuração específica o impeça. Entretanto, quando ocorre vazamento de memória, não há nada a ser coletado. Em ambiente de produção o problema mais comum decorre do uso do valor padrão da PermGen: 64MB, um tamanho muito baixo. Como forma de remediar esse problema, normalmente se configura o tamanho de 256MB.

Em seu email na lista de desenvolvimento do HotSpot, Jon Masamitsu explica o que irá mudar no Java 8 e a remoção da PermGen. Algumas partes, como as Strings internas, foram movidas para a heap normal já existente no Java 7. No Java 8, as estruturas restantes serão movidas para uma região de memória nativa chamada "Metaspace", que crescerá automaticamente por padrão e será coletada pelo garbage collector. Haverá duas flags: MetaspaceSize e MaxMetaspaceSize.

A pedido do InfoQ.com, Jon Masamitsu explicou o objetivo por trás dessa nova arquitetura:

Um objetivo da remoção da PermGen foi para que os usuários não tivessem que se preocupar em dimensionar o tamanho correto dessa área.

Configura-se a flag MetaspaceSize para um valor maior que o padrão se a aplicação precisar de espaço maior para armazenar dados de classes. Isso evita algumas execuções do garbage collector durante a inicialização. Não há necessidade de realizar essa configuração a menos que se queira evitar ao máximo a execução do garbage collector.

Configura-se a flag MaxMetaspaceSize para limitar o espaço reservado para armazenar os dados de classes. Essa configuração pode ser realizada quando existirem suspeitas de vazamento de classloaders e for desejável parar a aplicação, antes que consuma excessivamente a memória nativa. Outro cenário de utilização ocorre quando há múltiplas aplicações rodando no mesmo servidor e for desejável limitar a quantidade de espaço que cada aplicação usa para armazenar dados de classes.

Assim MetaspaceSize pode afetar as primeiras execuções do garbage collector e não deve ser importante na maioria dos casos. Assim se assemelha com a velha flag PermSize.

Quando a flag MaxMetaspaceSize é configurada, o espaço reservado ainda pode ficar sem memória, o que causará o erro "java.lang.OutOfMemoryError: Metadata space". Devido à possibilidade de vazamentos em classloaders, parece sensato configurar um limite semelhante ao que era configurado com MaxPermSize. De forma parecida com o que acontece no PermGen, o log detalhado do garbage collector (verbose) imprime o consumo atual do Metaspace. Usando as flags PermSize ou MaxPermSize via linha de comando será apresentado um aviso, instruindo o usuário a mudar para as novas flags.

Como o conceito de Metaspace e PermGen é na maior parte do tempo o mesmo, um administrador atualizando o Java 7 para Java 8 pode simplesmente mudar as flags executando sed 'e/Perm/Metaspace/g'.

Conclusões

No geral, essa mudança parece ser menor do que o esperado. Ao tornar o Metaspace ilimitado por padrão, evita-se a definição de uma quantidade de memória default muito pequena, porém ainda será necessário configurar um tamanho máximo para garantir a estabilidade do sistema. Felizmente, é possível reusar a configuração de PermSize e MaxPermSize, e apenas renomear a flag. Por outro lado, a mudança de heap gerenciado do Java para memória nativa significa que há muito menos informações úteis no heap dump para resolver os problemas, assim como foi levantado por Kirk Pepperdine. Os vazamentos de classloaders ainda podem acontecer, como antes.

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

Dê sua opinião

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber menssagens dessa discussão
Comentários da comunidade

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber menssagens dessa discussão

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber menssagens dessa discussão

Dê sua opinião

Conteúdo educacional

Feedback geral
Bugs
Publicidade
Editorial
InfoQ Brasil e todo o seu conteúdo: todos os direitos reservados. © 2006-2013 C4Media Inc.
Política de privacidade
BT