java.lang.OutOfMemoryError: PermGen space
7 Comentários Publicado por Guilherme em sábado, outubro 07, 2006 at 3:33 PM.
Continuo em busca de uma solução para esse memory leak. Memory leak em java pode ser causado por um objeto que não é coletado depois que não é mais necessário ou não está mais ativo. Com isso, a performance do computador é prejudicada, pois há uma redução na quantidade de memória disponível.
Ao ler os posts atualizados do Bloglines me deparei com o seguinte post: debugging PermGen OutOfMemoryError problems in windows
Nesse post o autor Rich Unger dá dicas de como debugar esse tipo de bug que é tão difícil de reproduzir. No post, o autor faz referência ao seguinte post do autor Gregg Sporar, que define os diferentes tipos de memory leaks que podem ocorrem em aplicações Java.
http://weblogs.java.net/blog/gsporar/archive/2006/09/javazone_sessio.html
Entre os três tipos, o que mais me interessa no momento é o: Repeatedly deploying my application to Tomcat causes it to run out of perm gen space - is there a problem with perm gen usage in Tomcat.
Parece que o TomCat possui esses problemas de perm gen mesmo, inclusive existe um cadastro de bug no bugzilla do TomCat 5: http://issues.apache.org/bugzilla/show_bug.cgi?id=33711
Para saber melhor onde pode estar ocorrendo o vazamento de memória, o autor indica a utilização do JConsole. O JConsole é uma ferramenta que utiliza instrumentação JMX para prover informações sobre performance e consumo de recursos de aplicações que rodam na plataforma Java.
Iniciando o JConsole
O JConsole pode ser encontrado em JAVA_HOME/bin, onde JAVA_HOME é o diretório onde o JDK foi instalado. O JConsole pode ser utilizado tanto para monitoramento de aplicações locais quanto aplicações remotas.
Monitoramento e Gerenciamento Local
Para habilitar o acesso local ao JMX, precisamos criar a seguinte propriedade quanto iniciarmos a JMV ou aplicação Java:
A Interface do JConsole
A interface do JConsole é composta por seis abas:
* Summary tab: exibe informações sobre a JVM e valores monitorados.
* Memory tab: exibe informações sobre o uso de memória.
* Threads tab: exibe informações sobre o uso de threads.
* Classes tab: exibe informações sobre o carregamento das classes.
* MBeans tab: exibe informações sobre MBeans.
* VM tab: exibe informações sobre a JVM.

Na aba Memory, podemos encontrar informações sobre o consumo e pools de memória:

Na aba Classes, podemos encontrar informações sobre o carregamento das classes, incluindo o total de classes carregadas, total de classes não carregadas, etc...

Até agora encontrei as seguintes possíveis soluções para esse problema:
* Utilizar a flag -XX:MaxPermSize para aumentar o tamanho de memória disponível (o default é 64M)
* Migrar para outro WebContainer (Jetty ou Resin)
* Mudar de implemetação de JDK, utilizar por exemplo a JRockit (Algumas pessoas dizem que após a mudança, esse problema não persiste)
Fontes:
http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html
Ao ler os posts atualizados do Bloglines me deparei com o seguinte post: debugging PermGen OutOfMemoryError problems in windows
Nesse post o autor Rich Unger dá dicas de como debugar esse tipo de bug que é tão difícil de reproduzir. No post, o autor faz referência ao seguinte post do autor Gregg Sporar, que define os diferentes tipos de memory leaks que podem ocorrem em aplicações Java.
http://weblogs.java.net/blog/gsporar/archive/2006/09/javazone_sessio.html
Entre os três tipos, o que mais me interessa no momento é o: Repeatedly deploying my application to Tomcat causes it to run out of perm gen space - is there a problem with perm gen usage in Tomcat.
Parece que o TomCat possui esses problemas de perm gen mesmo, inclusive existe um cadastro de bug no bugzilla do TomCat 5: http://issues.apache.org/bugzilla/show_bug.cgi?id=33711
Para saber melhor onde pode estar ocorrendo o vazamento de memória, o autor indica a utilização do JConsole. O JConsole é uma ferramenta que utiliza instrumentação JMX para prover informações sobre performance e consumo de recursos de aplicações que rodam na plataforma Java.
Iniciando o JConsole
O JConsole pode ser encontrado em JAVA_HOME/bin, onde JAVA_HOME é o diretório onde o JDK foi instalado. O JConsole pode ser utilizado tanto para monitoramento de aplicações locais quanto aplicações remotas.
Monitoramento e Gerenciamento Local
Para habilitar o acesso local ao JMX, precisamos criar a seguinte propriedade quanto iniciarmos a JMV ou aplicação Java:
com.sun.management.jmxremote
Por exemplo, para utilizarmos o JConsole com o TomCat devemos executar os seguintes comandos na linha de comando:TOMCAT_HOME\bin> set JAVA_OPTS=-Dcom.sun.management.jmxremote
TOMCAT_HOME\bin> catalina start
Após executar os comandos acima, inicie o JConsole e note que há uma configuração na aba Local apontando para a classe: org.apache.catalina.startup.BootStrap. Isso indica que o JConsole já pode monitorar o TomCat. Em seguida cliquem em Connect.TOMCAT_HOME\bin> catalina start
A Interface do JConsole
A interface do JConsole é composta por seis abas:
* Summary tab: exibe informações sobre a JVM e valores monitorados.
* Memory tab: exibe informações sobre o uso de memória.
* Threads tab: exibe informações sobre o uso de threads.
* Classes tab: exibe informações sobre o carregamento das classes.
* MBeans tab: exibe informações sobre MBeans.
* VM tab: exibe informações sobre a JVM.

Na aba Memory, podemos encontrar informações sobre o consumo e pools de memória:

Na aba Classes, podemos encontrar informações sobre o carregamento das classes, incluindo o total de classes carregadas, total de classes não carregadas, etc...

Até agora encontrei as seguintes possíveis soluções para esse problema:
* Utilizar a flag -XX:MaxPermSize para aumentar o tamanho de memória disponível (o default é 64M)
* Migrar para outro WebContainer (Jetty ou Resin)
* Mudar de implemetação de JDK, utilizar por exemplo a JRockit (Algumas pessoas dizem que após a mudança, esse problema não persiste)
Fontes:
http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html
Esse é um problema do classloader do tomcat. tem uma issue para corrigir isso no bugtrack
O link para a issue é: http://issues.apache.org/bugzilla/show_bug.cgi?id=40679
Olha, ....
Na verdade tive o seguinte problema:
Na JRockit vc recebe um DUMP do tamanho do mundo com todas as informações baixo nível e a seguinte mensagem de erro:
Error Message: Illegal memory access. [54]
Aí mudei para o Mustang e recebi essa:
java.lang.OutOfMemoryError: PermGen space.
Pois é, o problema é o da JVM mesmo.
Dependendo da Aplicação vc deve usar a option de comando para aumentar a Perm Generation.
Acho muito exagero a troca de conteiner , ainda mais reviver um que ja morreu a anos o resin.. E trocar de JVM,,a fala serio amigo...
La no banco do brasil a gente coloca 512 o permgem pq nao tem uma "solucao" é pouco divulgado pela sun...
Ola Galera... eu enfrento esse problema de PermGen a muito tempo.. e nao so no tomcat...
Sou arquiteto de Software especializado em Java.. e geralmente trabalho com aplicacoes de Grande porte..
Ja tive esse problemas em aplicacoes sobre Weblogic com heapsize de 5Gb .. e 1Gb de Perm size...
Esse problema acontece qdo vc usa eclipse... qdo vc usa ate mesmo o iReports...
Eu acredito q o problema nao esta nessas aplicacoes.. e sim no exagero.. do uso de alguns recursos..
Vamos analizar o problema...
Primeiro ponto, na minha opnião PermGen outOfMemory errors nao sao MemoryLicks..
O nome PermGen Space ja diz : "Espaço Permanente..."
O Perm é um espaço de memória da VM utilizado para o carregamento das classes/bytecode e é fixo .. o Garbage collector não atua sobre essa área.. ele nao limpa objetos ali... então não é um memorylick.. e sim um problema de DIMENSIONAMENTO...
Agora... se é um espaço fixo.. usado para o carregamento do bytecode.. esses erros deveriam ocorrer no startup das aplicacoes.. onde se supõe q o bytecode é carregado.. e nao no decorrer do tempo...
Na verdade.. nao é no startup q todo o bytecode é carregado..
Pela natureza dinâmica de Java.. muitas classes podem ser carregadas on-the-fly usando um Class.forName("..") por exemplo...
Agora na minha opnião... o Grande vilão... q vem causando a maioria dos erros de PermGen são aplicações q utilizando a geracao de byteCode em runtime .. como javasist (do JBoss), CGLIB (usado pelo hibernate e Spring) e a propria criacao de proxys pela VM...
Imagina o seguinte fluxo de vida para uma aplicacao Spring + Hibernate...
Qdo vc da o deploy a primeira vez.. e comeca a utilizar.. o container carrega as classes.. REAIS.. da sua aplicacao e de suas dependencias..
qdo vc comeca a utilizar a aplicacao o Spring vai criar algumas classes em runtime.. para ser os proxys.. de aspecto da sua aplicacao para controlar transacao etc...
o Hibernate tb vai criar classes proxy para suas entidades.. para fazer lazyLoading.. etc..
qdo vc da re-deploy de uma aplicacao dessas ... a session factory do hibernate e a beanFactory do Spring.. ja nao vao conhecer as classes geradas anteriormente.. e vao gerar novamente todas estas classes/proxys novamente.. e isso vai enchendo o PermGen Space... e como eu disse antes o Garbage Collector NUNCA limpa este espaço.
Para concluir ... na minha opniao o problema HOJE é de dimensionamento.. vc deve entender se sua aplicacao gera bytecode em runtime.. e saber q ela vai exigir mais PermGen Space ...
Eu disse o problema HOJE .. por q é assim q as VMs se comportam.. talvez no futuro esse problema nao ocorra... com uma implementacao mais inteligente do PermGen Space.. talvez..
Bem elucidativo este último comentário, mas, memorylick? =)
Tambem estou tendo este problema.
Na verdade o GC passa no PermGen, mas usando o Metodo MarkAndSweep, e como 99% das Classes no PermGen são necessarias e nao foram marcadas como lixo, o PermGen cresçe desse jeito.