Perfomance - Poupando memória!

21 respostas
neeryck

Fala galera!!

while (isTeste){
  
 for(int i = 0; i < 10000; i ++){

   Object  a = new Object();
    //Todo meu tratamento com o objeto

 }

}
Object a = null;

while (isTeste){
  
 for(int i = 0; i < 10000; i ++){

     a = new Object();
    //Todo meu tratamento com o objeto

   a = null;

 }

}

Qual é a melhor forma?? Qual vcs utilizam habitualmente??? Tem exemplos??

[]'s

21 Respostas

C

Não há diferença nenhuma.
Assim que a JVM descobrir que ninguém mais aponta para o objeto ‘a’, ela vai tirar ele da memória, e como a cada iteração ela vai fazer isso, não tem diferença.

T

Use a primeira forma (deixar a variável com o menor escopo possível).
A segunda (onde você inadvertidamente pode acabar estendendo o escopo e o tempo de vida da variável) pode até gastar mais, em vez de menos memória.

rodrigo.bossini

Aproveitando este tópico, com uma questão parecida.

Dados:

public void metodo (){
  for ( int i = 0; i < 1000; i++){
     new MeuObjeto().executaAlgo();
  }
}

e

public void metodo(){
  MeuObjeto ob = new MeuObjeto();
  for ( int i = 0; i < 1000; i++){
     meuObjeto.executaAlgo();
  }
}

é claro que na primeira versão um novo objeto é criado a cada iteração. E na segunda versão somente um objeto é criado.
Porém, na primeira versão, assim que o objeto é criado e executa seu método, ele já se torna elegível para o GC.
Na segunda versão, o mesmo objeto é mantido durante todo o escopo do método.

Qual a melhor abordagem?

M

Sinceramente os exemplos citados “Gastam” mais ou menos linhas e não tem nada a ver com poupar memória…
nem sempre instanciar e logo depois “matar” a variável irá te ajudar a poupar memória… em dispositivos móveis com hardware realmente limitado por vezes é muito mais vantajoso ter a variavel sempre instanciada que fazer isso varias vezes sempre que você for usa-la… já me deparei com dispositivos que ao fazer esse tipo de prática instanciar/matar fragmentava a memória disponível e acabava lançando a exceção outOfMemory mesmo com “memória livre” … cada caso é um caso.

neeryck

Vlw brother!!

Concordo que cada caso…

Vc parou pra pensar que deve ser por isso que postei aqui e não em “Java Micro Edition (Java ME)” ???

Tente trazer algo produtivo pra galera do GUJ quando postar e diga o pq, exemplificando, argumentado, sustentando seu ponto de vista!!

[]'s

T

O Entanglement postou um programa ( http://www.guj.com.br/posts/list/145548.java#784298 ) onde ele mostra que em determinados casos é muito melhor usar StringBuilder (ou StringBuffer se você estiver usando Java 1.4 ou anterior) que efetuar a concatenação de strings com +=.

bombbr

rod.attack:

Qual a melhor abordagem?

Segunda abordagem.

No primeiro caso serão criados vários objetos que ocuparão memória e tempo do GC.

rodrigo.bossini

bombbr:
rod.attack:

Qual a melhor abordagem?

Segunda abordagem.

No primeiro caso serão criados vários objetos que ocuparão memória e tempo do GC.

E se for um objeto grande e o corpo do método for bastante grande também depois do laço, e ainda não utilizar mais o objeto depois do laço?

ViniGodoy

rod.attack:

é claro que na primeira versão um novo objeto é criado a cada iteração. E na segunda versão somente um objeto é criado.
Porém, na primeira versão, assim que o objeto é criado e executa seu método, ele já se torna elegível para o GC.
Na segunda versão, o mesmo objeto é mantido durante todo o escopo do método.

Qual a melhor abordagem?

Em termos de performance, tanto faz. Use a que for mais lógica para você.

Engano, seu. Serão criados vários objetos, mas utilizando apenas um único espaço de memória.

O que ocorre é que o garbage collector controla gerações de objetos. Existe a geraçãode objetos “novos” que ficam numa área de memória rápida e facilmente reutilizável. E a geração de objetos “velhos”, que vão para um local mais definitivo.

Quando esse objeto é morto, ele não é imediatamente coletado, pois ainda está na área nova. Quando vc faz um novo new, aquela área de memória será reutilizada, sem custo de uma nova alocação, ou sem gastar nova memória. O java apenas rodará uma função nativa do SO para zerar aquela região, e em seguida o construtor, o que geralmente tem um custo ridiculamente barato.

Quem quiser saber mais:


Essa é uma das características que ajudam a tornar aplicações Java tão performáticas quanto aplicações C++, embora exista o overhead da VM.

ViniGodoy

rod.attack:
bombbr:
rod.attack:

Qual a melhor abordagem?

Segunda abordagem.

No primeiro caso serão criados vários objetos que ocuparão memória e tempo do GC.

E se for um objeto grande e o corpo do método for bastante grande também depois do laço, e ainda não utilizar mais o objeto depois do laço?

Pelo que expliquei acima, é sempre melhor manter o escopo o mais curto possível.

rodrigo.bossini

Li os links, mas para mim ainda são muito avançados, rs. Eu chego lá.
Usando o exemplo que postei acima, com um new dentro de um for.

Digamos que haja dois new’s dentro do for. Assim:

public void metodo(){
   for (blablabla){
       new MeuObjeto1().execute();
       new MeuObjeto2().execute();
   }
}

Na próxima iteração o GC já saberá que as áreas ocupadas pelos objetos criados na iteração anterior já estão disponíveis?
Ele utilizará a área de memória somente se o objeto novo for do mesmo tipo do objeto antigo, ou isso não tem nada a ver?
Outra coisa, eu crio um objeto com new, sem atribuir esse objeto a nenhuma referência. E chamo um método nesse objeto.
O método fica executando e eu não tenho nenhuma referência para este objeto no meu código.
O GC somente coleta o objeto depois que o método terminar?

ViniGodoy

Sim. Assim que a função terminar, o gc sabe que pode reutilizar a memória.

Se for exatamente do mesmo tamanho. Pro gc o que importa é a área reservada, não a classe.

Outra coisa, eu crio um objeto com new, sem atribuir esse objeto a nenhuma referência. E chamo um método nesse objeto.
O método fica executando e eu não tenho nenhuma referência para este objeto no meu código.
O GC somente coleta o objeto depois que o método terminar?

Sim. Existirá uma referência invisível ao objeto, enquanto ele estiver sendo executado.

rodrigo.bossini

Sim. Assim que a função terminar, o gc sabe que pode reutilizar a memória.

Você quis dizer o método que o objeto executa, ou o método que contém o for?

ViniGodoy

Na verdade, assim que o objeto sair de escopo. No caso do seu for, pode até mesmo ser que o segundo construtor já reutilize a memória do primeiro (não sei exatamente qual é o escopo da referência invisível, mas creio que seja o menor possível. Ele vai ser no máximo do tamanho do método do objeto).

neeryck

Muito bem senhores!
Imaginem um StringBuilder com milhões de String’s concatenadas.

meuStringBuilder.delete(0,meuStringBuilder.length() - 1);

OU

meuStringBuilder = new StringBuilder();

Qual (ainda que mínimo) traria maior beneficio em performance e pq??
Thank’s in advance!

[]'s

ViniGodoy

Só fazendo um profiling para identificar.

Mas acho que nenhum deles teria uma diferença significativa de tempo de execução.

neeryck

Entendi…
Obrigado Viny!

[]'s

neeryck

Ahh!

Tem alguma ferramenta boa e gratis para profiling??

[]'s

ViniGodoy

Sim, tem o Visual VM, que vem com o JDK 6 (está na pasta bin do seu JDK). E tem o profiler do Netbeans também.

neeryck

Digamos que eu precise de uma (somente uma) String qualquer “foo” e essa mesma String seja uma constante em outra classe “ClasseConstantes.java”. Minha dúvida é:
Devo utilizar somente a String :

objetoQualquer.get("foo");

Ou:

objetoQualquer.get(ClasseConstantes.REFERENCIA_A_FOO);

A dúvida remete aos import’s que são feitos (carregando a classe) na classe que utilizarei.
Deve ser coisa mínima também mas, deixou-me com a dúvida!
Obrigado!

[]'s

ViniGodoy

No caso de Strings, ambos os códigos provavelmente gerarão resultados idênticos.
Para outros objetos, se forem imutáveis, é melhor usar a segunda alternativa.

Criado 14 de janeiro de 2010
Ultima resposta 25 de jun. de 2010
Respostas 21
Participantes 7