Dúvida performace, memória

11 respostas
neno

Pessoal, ajudem em uma duvida

Se eu tenho um looping que roda um determinado numero de vezes, e toda vez que eu passe nesse looping eu instancio um objeto, o que acontece com o mesmo no proximo looping?

ex:

Objeto o = null; while(true){ o = new Objeto(); //trabalha o objeto }

O que a contece, a refeência vão acumulando na memória? Aquele espaço namemoria que aloquei na passa anterior é liberado quando eu dou um new Objeto()?
O GC é acionado? duvidas, duvidas…

11 Respostas

P

A cada iteração, um novo objeto é carregado na memória. O anterior fica desreferenciado e, portanto, torna-se elegível para ser coletado pelo GC. Mas atenção: isto não significa que ele será imediatamente coletado.

Por este motivo, a instanciação de objetos dentro de loops é considerada má prática. Faça isto somente quando for absolutamente necessário.

Adelar

O GC é acionado em intervalos de tempo. Se houverem objetos que não são referenciados no programa estes serão desalocados, nestes períodos que o GC é chamado. Assim, chamando new não significa que será chamado o GC, a não ser que tenha chegado ao limite de memória, daí o GC será chamado automaticamente para tentar liberar memória para o novo objeto.

[]'s

InicianteJavaHenriqu

pango:
A cada iteração, um novo objeto é carregado na memória. O anterior fica desreferenciado e, portanto, torna-se elegível para ser coletado pelo GC. Mas atenção: isto não significa que ele será imediatamente coletado.

Por este motivo, a instanciação de objetos dentro de loops é considerada má prática. Faça isto somente quando for absolutamente necessário.

Bom saber :slight_smile: faço isto direto :oops: No caso e se eu chamar uma conexão com BD (fora de um loop) e não mandar finalizar (porque não sei, tentei com try-catch e no finally coloquei conexaoBD.close e não deu certo) todas as conexões ficam na RAM ou quando chamo outra a anterior é anulada e libera memória?

P

InicianteJavaHenrique:
pango:
A cada iteração, um novo objeto é carregado na memória. O anterior fica desreferenciado e, portanto, torna-se elegível para ser coletado pelo GC. Mas atenção: isto não significa que ele será imediatamente coletado.

Por este motivo, a instanciação de objetos dentro de loops é considerada má prática. Faça isto somente quando for absolutamente necessário.

Bom saber :slight_smile: faço isto direto :oops: No caso e se eu chamar uma conexão com BD (fora de um loop) e não mandar finalizar (porque não sei, tentei com try-catch e no finally coloquei conexaoBD.close e não deu certo) todas as conexões ficam na RAM ou quando chamo outra a anterior é anulada e libera memória?

Cara,

A sua chamada a conexaoBD.close() dentro do finally não funcionou porque este método também lança uma exceção. Por este motivo, ele próprio deve estar dentro de um try/catch:

conexaoBD = ... ; // instancia a conexão, ou recupera a mesma de algum lugar, como um pool

try {

     for (int i = 0; i < colecao.size(); i++) {
          
          // grava objetos no BD

     }
}
catch (Exception exception) {

     //trata erros ocorridos dentro da iteração

}
finally {

     try {
          conexaoBD.close();
     }
     catch (Exception exception) {
          // trata erros ocorridos ao tentar fechar a conexão
     }
}

Por fim, uma dica: conexões são extremamente caras para se criar, tanto em termos de tempo quanto de uso de processador. Por este motivo, recomenda-se que:

  1. Em aplicações JEE, se utilize um pool de conexões gerenciado pelo container;
  2. Em aplicações JSE, se crie uma única conexão (durante a inicialização do programa, por exemplo), que será fechada no encerramento do programa.
Jose111

Em aplicações JSE também é recomendado usar pool de conexões, já que em determinados momento uma unica conexão não será suficiente e o tempo gasto para criar novas conexões é muito grande assim atrapalhando na perfomace da aplicação.

P

Jose111:

2) Em aplicações JSE, se crie uma única conexão (durante a inicialização do programa, por exemplo), que será fechada no encerramento do programa.

Em aplicações JSE também é recomendado usar pool de conexões, já que em determinados momento uma unica conexão não será suficiente e o tempo gasto para criar novas conexões é muito grande assim atrapalhando na perfomace da aplicação.

Acredito que em aplicações desktop situações do tipo que você descreveu são mais raras, mas ainda, é uma solução válida.

InicianteJavaHenriqu

:?:

InicianteJavaHenriqu

Obrigado pango e a todos pela dica, não tinha pensando em colocar try-catch dentro do finally, pois achava que em um único try-catch tratava-se todas as excessões. Obrigado pela dica consegui fazer com o seu exemplo.

Só não sei o que é pool (piscina :?: ). Eu programa somente em J2SE (não sei ainda sobre J2ME e J2EE :frowning: ) enfim…
Eu fiz um método para conexão :

private Connection conexao;
private Statement ponteConexaoDados;
ResultSet dados;

private void conexaoBD() {
 try {  
        Class.forName("com.mysql.jdbc.Driver");
        conexao = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/BD?user=root&password=root");
        ponteConexaoDados= (Statement) con.createStatement();    
        } catch (ClassNotFoundException erro) {
        conexao = null;
        } catch (SQLException erro) {
        conexao = null;
        }finally {
             try {  
                  conexaoBD.close();  
                 } catch (Exception exception) {  
                    conexao = null;
                }  
}

Assim toda vez que preciso fazer um executeQuery ou executeUpdate (que são muitas vezes) eu chamo o método conexaoBD(), este pool é algo semelhante a isto :?: :?: :?:

Por enquanto obrigado pelas dicas.

ViniGodoy

Resposta simplista:
Seu objeto fica desreferenciado assim que chegar na última linha do while, pois a variável sai de escopo, portanto o garbage collector pode remove-lo, desalocando a memória ocupada por ele. Em seguida, o while reinicia e um novo objeto é criado. Aloca-se novamente memória e roda-se o contrutor sobre ela.

Resposta detalhada:
Todo objeto é criado na região de vida curta do garbage collector. Apenas objetos que sobrevivam a muito tempo de execução são movidos para a área de vida longa.
Caso um objeto de vida curta seja excluído, não há liberação física de memória. Sua área fica disponível, para que um outro objeto de vida curta a habite. Como no seu código, um novo objeto de mesmo tamanho irá ser criado na sequência, essa mesma área será reaproveitada e, ao invés de reservar novamente memória, o garbage collector só irá rodar o construtor para limpar aquele endereço previamente reservado.

Dessa forma, seu programa terá um custo de alocação e desalocação próximo de 0 para esse tipo de situação (afinal, efetivamente o java só fica usando a mesma área de memória, e não criando e recriando objetos). É por isso que um programa que tenha uma estrutura como essa, que cria e destrói um mesmo objeto num loop, tem uma excelente performance em java, e uma péssima performance em C++ (a menos, claro, que vc implemente sua própria política de alocação de memória).

Vale lembrar que alocar e desalocar memória é um custo altíssimo, e por isso esse tipo de estratégia é tão eficiente. Os projetistas da Sun, ao pesquisar sobre o comportamento dos objetos, perceberam que era muitíssimo comum criações e destruições dessa forma (mais comum até do que a existência de objetos de vida longa), e isso motivou essa otimização no gc.

A resposta simplista ainda é correta pois, conceitualmente, toda essa ginástica é apenas uma inteligente otimização. Na prática, para nós programadores mortais, o que o java parece estar fazendo é simplesmente alocar e reservar memória novamente.

Mais informações:


fabiofalci

Mais uma bela dica em Vini. Favoritado! :wink:

ViniGodoy

Como expliquei, em Java, não há diferença entre fazer isso dentro ou fora do loop, graças a política de gerações do GC.
Por isso, em java, é considerado boa prática fazer dentro do loop, pois isso reduz o escopo da variável do objeto.

Obrigado! Na verdade, vale muito a pena ler todos os artigos do Goetz. Afinal, ele é o pai da criança :slight_smile: :
http://www.briangoetz.com/pubs.html

Criado 14 de abril de 2011
Ultima resposta 15 de abr. de 2011
Respostas 11
Participantes 7