Vazamento de memória - Pais & Filhos

6 respostas
PauloBrito

Este código irá criar uma condição onde o objeto pai nunca estará disponível para gc?

class Pai {
   Vector<Filho> filhos = new Vector<Filho>;

   public void newFilho() {
      filhos.add(new Filho(this));
   }
}

class Filho {
   Pai pai;

   public Filho(Pai pai) {
      this.pai = pai;
   }
}

Pai pai = new Pai();
pai.newFilho();

System.gc();

// 'pai' ainda existe?

6 Respostas

peczenyj

Ok, vc criou uma referencia circular.

Enquanto houver referencias fortes para o objeto pai, ele não sera recolhido.

Eu fiz um exemplo usando java.lang.ref.WeakReferences:
class Teste{
//falta um nome melhor...
	public static WeakReference<Pai> xxx(){		  
		  Pai pai = new Pai();
		  WeakReference<Pai> ref = new WeakReference<Pai>(pai); 		  		  	      			
	      
	      pai.newFilho();
	      return ref;
	}
	
	public static void main(String... x){
		  Runtime r = Runtime.getRuntime();
		  WeakReference<Pai> ref = xxx();
	      r.gc();
	      
	      if(ref.get() == null){
	    	System.out.println("pai foi recolhido pelo garbage collector");  
	      } else{
	    	System.out.println("pai ainda existe");
	      }
	}
}

Comente o r.gc() e veja a diferença. Espero não estar enganado quanto ao meu exemplo e ao codigo, afinal a api de references eu não domino totalmente.

PauloBrito

Beleza, peczenyj. Adaptei seu exemplo ao meu anterior e deu pra ver que funciona mesmo. Eu estava usando WeakReferences no meu projeto, mas de uma maneira completamente equivocada, confesso.

Uma última dúvida: esta é a maneira mais usual de referenciar um objeto acima na hieraquia? Por exemplo:

class Tecla {
   ...

   WeakReference<Teclado> funcionario.getTeclado() {
      ...
   }

   ...
}

Isso é usual? Ou há uma outra técnica para isso? Costumo criar containers usando Vector. No caso acima, seria algo assim:

class Tecla {
   int codigo;
  
   public Tecla(Teclado teclado, int codigo) {
      this.teclado = teclado;
      this.codigo = codigo;
   }

   public int getCodigo() {
      return this.codigo;
   }

   public Teclado getTeclado() {
      return this.teclado;
   }
}

class Teclado extends Vector<Teclado> {
   String tipo = "ABNT2";

   public getTipo() {
      return this.tipo;
   }
}

class ProcessadorTeclado {

   public char pressiona(Tecla tecla) {
      if (tecla.getTeclado().getTipo().equals("ABNT2") && tecla.getCodigo = 233)
         return "ç"
     else ....
   }
}

Há alguma forma melhor de fazer isso ou só usando WeakReferences mesmo?

peczenyj

Vou te responder de uma forma totalmente superficial: sua forma de processar tais informações, aparentemente, abusam do paradigma imperativo - o que não é ruim. São muitos ifs. Vc poderia estudar uma forma de trabalhar com o Pattern Strategy ou utilizar um “motor de regras”, um rule engine tipo o Drools ou algo mais simples como hashtables de regras.

ex (pseudocodigo):

teclado[TiposTeclado.ABNT2][223] = 'ç';

Outra coisa, o tipo do Teclado ser uma string é um pouco “pobre”. IMHO vc poderia ter uma Enumeração de tipos, coisa que o java suporta desde a versão 5. Evita, por exemplo, vc ter problemas com ABNT2 e abnt2 ou ABnT2. Se não puder ter enumerações (java 1.4 ou inferior), pode ter atributos publicos finais de uma classe ou interface para representar estas constantes.

De uma lida no algoritmo de RETE, talvez te dê algumas ideias interessantes. Sinto não poder ajudar mais.

PauloBrito

Este código “do teclado” foi só uma maneira de exemplificar o uso da referência ao container. Mas obrigado pelas dicas.

peczenyj

Pois então, fico pensando pq vc gostaria de ter uma weakreference desse objeto, aparentemente ele é nobre demais para vc se dar ao luxo de perde-lo via garbage collector.

Vc esta trabalhando com situações criticas tipo pouca memória?

PauloBrito

Na verdade não gostaria! Mas parece que é o único modo de não causar vazamento de memória, seu eu preciso de referência circular.

Criado 12 de junho de 2009
Ultima resposta 14 de jun. de 2009
Respostas 6
Participantes 2