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
A
alan_pjr
Utilizar um try{ } catch{ } finally{ } para garantir o fechamento do recurso também pode ajudar.
R
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.
F
FernandoFranzini
Sim…retire todos os JAR’s que não estão sendo usado, uma vez que é carregado no classloader, gastando PermGem.
R
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.
F
FernandoFranzini
O problema é memoria ou CPU?
R
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.
F
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.
G
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.
F
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.
R
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.