Memória JAVA não abaixa

13 respostas
rsaleixo

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.

public void gerarRelatorio() throws JRException, SQLException, FileNotFoundException, IOException, ClassNotFoundException {
        
        try {

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

            /* HashMap de parametros utilizados no relatório. Sempre instanciados */
            Map parameters = new HashMap();
            parameters.put("dataInicio", format.format(getDataInicio()));
            parameters.put("dataFim", format.format(getDataFim()));
            
            String where = "";

            if(codigoRegiao > 0){
                where = " and regiao.idRegiao = " + codigoRegiao + " ";
            }

            parameters.put("where", where );
            Class.forName("com.mysql.jdbc.Driver");
            Connection varConexao = DriverManager.getConnection("jdbc:mysql://localhost:3306/gope","root","java");

            byte[] bytes = JasperRunManager.runReportToPdf(PropertiesLoaderImpl.getPropriedade("CAMINHOJASPER") +      "AtendimentoPorPeriodo.jasper",parameters,varConexao);

            HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
            response.setHeader("Content-Disposition", "attachment;filename=\"" + "Analise_SLA "+new SimpleDateFormat("yyyyMMddhhmmss").format(new Date())+".pdf" + "\"");
            response.setContentType("application/pdf");
            response.setContentLength(bytes.length);

            ServletOutputStream ouputStream = response.getOutputStream();
            ouputStream.write(bytes, 0, bytes.length);
            ouputStream.flush();
            
            
            ouputStream.close();
            varConexao.close();

            FacesContext.getCurrentInstance().responseComplete();

        } catch (Exception e) { System.out.println("Erro em gerar o relatórios: " + e.getMessage()); }
       

}

13 Respostas

FernandoFranzini

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?

  1. 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

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.

rsaleixo

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:

  1. Nivel de memoria esta abaixo da sua demanda?
  2. Sua solução não esta liberando memoria devidamente?
  3. 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.

Criado 3 de novembro de 2011
Ultima resposta 8 de nov. de 2011
Respostas 13
Participantes 6