Estou com uma aplicação em JSF rodando em uma VM, toda vez que alguém está gerando relatório a memória do JAVA aumenta e não volta ao normal. Isso vai acontecendo até travar a maquina.
publicvoidgerarRelatorio()throwsJRException,SQLException,FileNotFoundException,IOException,ClassNotFoundException{try{SimpleDateFormatformat=newSimpleDateFormat("yyyy-MM-dd");/* HashMap de parametros utilizados no relatório. Sempre instanciados */Mapparameters=newHashMap();parameters.put("dataInicio",format.format(getDataInicio()));parameters.put("dataFim",format.format(getDataFim()));Stringwhere="";if(codigoRegiao>0){where=" and regiao.idRegiao = "+codigoRegiao+" ";}parameters.put("where",where);Class.forName("com.mysql.jdbc.Driver");ConnectionvarConexao=DriverManager.getConnection("jdbc:mysql://localhost:3306/gope","root","java");byte[]bytes=JasperRunManager.runReportToPdf(PropertiesLoaderImpl.getPropriedade("CAMINHOJASPER")+"AtendimentoPorPeriodo.jasper",parameters,varConexao);HttpServletResponseresponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();response.setHeader("Content-Disposition","attachment;filename=\""+"Analise_SLA "+newSimpleDateFormat("yyyyMMddhhmmss").format(newDate())+".pdf"+"\"");response.setContentType("application/pdf");response.setContentLength(bytes.length);ServletOutputStreamouputStream=response.getOutputStream();ouputStream.write(bytes,0,bytes.length);ouputStream.flush();ouputStream.close();varConexao.close();FacesContext.getCurrentInstance().responseComplete();}catch(Exceptione){System.out.println("Erro em gerar o relatórios: "+e.getMessage());}}
Ja respondemos muitas pessoas na mesma situação…segue minha resposta padrão:
java.lang.OutOfMemoryError: Java heap space:
Aplicação java esta precisando gastar mais memoria do que a alocada para JVM. Por isso acontece o erro de falta de memoria!
Trabalhar com memoria no Java é como uma brincadeira de criança…
a memoria é copo com um tamanho determinado.
cada vez que é criado uma variavel ou objeto (new), seria como se colocasse um gotinha ou gota de água nesse copo.
Como funciona?
Quando vc inicia a aplicação, ja acontece um gasto com um pouco de água…tipo uns 20% do copo (pelos gastos do objetos iniciais)
Enquanto a aplicação ta rodando, vai criando e executando os objetos, ou seja, vai enchendo de água esse copo.
Quando a água começa ficar em media acima dos 70% do tamanho disponivel ocupado, o GC ja vai se mover tentando retirar/derramar essa agua do copo (retirar os objetos sem referencia)
Se o gc conseguir, ele vai esvaziar o possivel e assim tudo volta ao ciclo repetitivo de uso. Vai usando e gastando denovo.
Se o gc não conseguir, a agua cai do copo e acontece o java.lang.OutOfMemoryError kkkkk
Motivos de Falta de Memoria?
A solução esta gastando memoria desenfreadamente. Como?
Falta de uma arquitetura correta padrão.
Desenvolver despreparado, implementando código que gaste sem o devido controle.
Como corrigir?
Aprender praticas de otimização.
Entender o funcionamento da solução em questão.
Alterar o codigo da aplicação, aplicando as melhores praticas diante de cada situação.
2 A solução esta gastando memoria corretamente, mas ainda não é suficiente. O que fazer?:
Se a aplicação ja esta 100% otimizada, a única coisa que pode ser feito é aumentar a memoria! A solução precisa de mais memoria!!!
Situação muito comum em aplicações web quando o numero de usuário simultâneo vai aumento com o tempo.
java.lang.OutOfMemoryError: PermGen
PermGen quer dizer que a area de memória da JVM de carga de classes estouro…muito normal de acontecer quando um container JEE tem muita classes dentro própria aplicação + os jar’s para carregar.
Mais comum ainda quando o container JEE tem varios wars sendo executado simultaneamente.
Para corrigir isso, aumente essa area de memoria nos parâmetros do inicio do seu container.
Veja que isso não é um erro, é muito normal uma vez que cada container JEE deve ser devidamente configurado para o determinado ambiente/cenario a ser usado.
OBS - alterar o eclipse.ini muda os parâmetros para o eclipse e não para o tomcat!!!
No seu caso vc tem alterar os parâmetros de inicialização do tomcat diretamente no arquivo dele.
Se caso o tomcat esta sendo executado direto do eclipse, vc consegue acrescentar os parametros no seguinte menu:
Abra as propriedades do server clicando 2 vezes em cima do sevidor na aba “Servers”
Abra as configurações chamada de “Open launch configuration”
Selecione a aba “Arguments”, no campo VM arguments acrescente todos os seus parâmetros que customizam a memoria: Exemplo: -XX:MaxPermSize=246m
alan_pjr
Utilizar um try{ } catch{ } finally{ } para garantir o fechamento do recurso também pode ajudar.
rsaleixo
Fiz várias correções no código e mesmo assim o aumento de memória continua.
Não pode ser a configuração do Glassfish ?
J
jonatex
Fera, estava com problema de memória também e verifiquei que na verdade eram as bibliotecas excessivas que constavam no meu projeto! Quando Retirei algumas, deu uma melhorada.
FernandoFranzini
Sim…retire todos os JAR’s que não estão sendo usado, uma vez que é carregado no classloader, gastando PermGem.
rsaleixo
Fiz alguns testes no fim de semana, acompanhei pelo JConsolte e percebi que o projeto não é está consumindo muito.
Mas o Java ainda continua crescendo, chega uma hora que a VM trava qdo o uso da cpu fica em 100% por causa do Java.
Tirei alguns JAR’s, mas a maioria deles estão sendo sendo utilizados. E ainda continua o problema.
FernandoFranzini
O problema é memoria ou CPU?
rsaleixo
O uso da memória do Java não parar de crescer, com isso o Uso de CPU vai subindo junto até travar a VM.
FernandoFranzini
Um solução tem que ter um nível de memoria adequado para seu demanda de acesso:
Podem ser 3 coisas erradas:
Nivel de memoria esta abaixo da sua demanda?
Sua solução não esta liberando memoria devidamente?
Opção 1 e 2 juntas.
Giulliano
Qual é a configuração de memória do seu glassfish ? Acredito que o problema seja no servidor e não na sua aplicação.
fabim
Sei que vai ser uma ajuda meio “inutil”, mas vc precisa olhar com cuidado seu codigo e verificar se existe algum memory leak.
Praticamente todas as vezes que me deparei com esse cenario era a aplicacao gastando memoria por más praticas mesmo de desevolvimento, que geravam objetos inelegiveis pra coleta, gasto desnecessario de recurso etc… nao é normal a memoria ficar sempre no talo, o normal é usar -> liberar.
rsaleixo
Vamos lá, abaixo todas tentativas que melhoram o desempenho da aplicação, mas a memória do Java continua subindo.
[i]
Já revisei todos os meus objetos do jpa e defini como Lazy todos relacionamentos.
Dei um clear em todos EntityManager que a aplicação executava.
Quando o GC é executado a memória da aplicação desce no zero, mas a do Java continua.[/i]
Estou pesquisando sobre a memória heap.
E encontrei muita gente falando pra aumentar a memória young.
Vou tentar entender mais sobre este assunto e aplicar este teste. Talvez seja mesmo a configuração do Glassfish.