Atribuindo null

Postado em 03. jan, 2007 por Paulo Silveira em Java

Um post bem curto sobre uma prática que aparece comumente em códigos por aí:

public void metodoQueListaUsuarios() {
  List<Usuario> lista = dao.pegaListaDeUsuarios();
  for(Usuario u : lista) {
    System.out.println(u.getNome());
  }
  lista = null; // pra que isso?
}

Essa atribuição da lista para null, como muitos de vocês sabem, é totalmente desnecessária, pois ao fim do método o escopo da variável lista termina e ela morre automaticamente, já que essa é uma variável de pilha. Achar que isto está ajudando o Garbage Collector é um engano.

Porém tem alguns casos que isto é aplicável. O primeiro é se lista fosse um atributo, e não uma variável local ao método. Mas se você está atribuindo null a um atributo no fim de todo método, ele tem grande potencial de ser refatorado para varíaveis locais.

O segundo caso é quando você tem um objeto X alocado no heap e não vai usá-lo mais, porém você ainda tem trabalho a fazer no escopo da variável que referencia X. O Garbage Collector não poderá coletar X, nem mesmo marca-lo para coleta, enquanto a sua referência existir, e pode ser que ela continue existindo por muito tempo, como no código abaixo:

public void metodoQueListaUsuarios() {
  List<Usuario> lista = dao.pegaListaDeUsuarios();
  for(Usuario u : lista) {
    System.out.println(u.getNome());
  }
  lista = null;
  dao.fazOperacaoDemorada();  // lista ainda em uso?
}

Neste caso faz sentido tentar liberar a variável o mais rápido possível. Caso contrário, durante a nossa dao.fazOperacaoDemorada(), o objeto estará presente na memória e não poderá ser coletado (as vezes, em vez de atribuir null, podemos obter o mesmo efeito criando um novo escopo com {}). Claro que essa atribuição merece ser documentada. Essa operacaoDemorada poderia ser mais grave ainda caso a thread vá ser colocada em wait.

Dizem também, mas aí já está além do meu conhecimento, que a virtual machine hoje em dia consegue detectar essas variáveis que não tem mais uso em um determinado escopo, eliminando-a antes mesmo que o seu escopo feche.

Paulo Silveira ()

Mais sobre o autor

Tags:

6 Respostas para “Atribuindo null

  1. Rodrigo Urubatan

    04. jan, 2007

    na verdade, no segundo caso também não seria necessário, pois podemos verificar até em tempo de debug, que logo depois do for, a variavel lista não é mais acessivel, ou seja, o compilador ja se livra dela automaticamente …

    outra coisa que poderia ser feita, é pelo menos neste caso, alterar o código para algo parecido com isto:

    public void metodoQueListaUsuarios() {
      for(Usuario u : dao.pegaListaDeUsuarios()) {

        System.out.println(u.getNome());
      }
      lista = null;
      dao.fazOperacaoDemorada();  // lista ainda em uso?

    }

    ou algo parecido, assim também não seria necessário o código extra … e pelo menos na minha opinião ficaria um pouco mais legivel, em algum momento eu descompilo os códigos a cima para comparar e ver o que o compilador realmente faz :D

  2. Paulo Silveira

    04. jan, 2007

    Urubatan, o debug pega, mas nao sei se o GC pega, como disse. Se alguem tiver o link para a otimizacao do JIT, ai eu fico convencido!

    E o codigo foi so um exemplo, claro que voce podia ter eliminado a variavel temporaria, mas imagine que nao pudesse. Ai voce tem duas solucoes, ou fazer o null, ou declara-la dentro de um outro escopo abrindo e fechando {} em volta do FOR e da declaracao

  3. Paulo Silveira

    04. jan, 2007

    O que eu quis dizer com criar um novo escopo seria isso:

    public void metodoQueListaUsuarios() {
      {
        List<Usuario> lista = dao.pegaListaDeUsuarios();
        for(Usuario u : lista) {
          System.out.println(u.getNome());
        }
      }
      dao.fazOperacaoDemorada()
    }

    eliminando o lista = null.

  4. Sami Koivu

    04. jan, 2007

    Muito legal o post, Paulo. Também vejo que muita gente parece estar um pouco confuso sobre essa atribuição de null e GC.

    No bytecode os escopos dos variáveis locais são definidos explicitamente definindo o começo do escopo e o tamanho do escopo num LocalVariableTable -atributo (ou LocalVariableTypeTable no caso dos generics).

    http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#5956

    Só que.. esse atributo não é requerido, acho que é só utilizado pelo debugger mesmo: “The LocalVariableTable attribute is an optional variable-length attribute of a Code (§4.7.3) attribute. It may be used by debuggers to determine the value of a given local variable during the execution of a method.”

    Então.. na verdade o compilador não ajuda a maquina virtual com essa questão de escopo. Pois na ausência de um LocalVariableTable o escopo definido no arquivo class seria o método inteiro. Isso em mente acho que a maquina virtual tem que determinar o escopo dos variáveis analisando o código. Isso parece estranho e portanto fiz um teste: Compilando com -g:none (instruindo o compilador a não incluir informação de debug)

    public void metodoQueListaUsuarios() {
    {
    List lista = dao.pegaListaDeUsuarios();
    for(Usuario u : lista) {
    System.out.println(u.getNome());
    }
    }
    dao.fazOperacaoDemorada();
    }

    e

    public void metodoQueListaUsuarios() {
    List lista = dao.pegaListaDeUsuarios();
    for(Usuario u : lista) {
    System.out.println(u.getNome());
    }
    dao.fazOperacaoDemorada();
    }

    produzem exatamente o mesmo código. Surpreendente, não?

  5. Sami Koivu

    04. jan, 2007

    Desculpem a falta de formatação :) E acrescentando que o teste e a teoria aplicam para Java 5, não tenho feito muita coisa com o Java 6 ainda.

  6. Hugo Vidal Teixeira

    09. jan, 2007

    Esse post me lembrou dos tempos em que eu programava em C++/Delphi e tinha que desalocar possíveis objetos no final dos métodos (delete/free). Boa lembrança.

    O que eu gostaria de lembrar aqui é que se o método pegaListaDeUsuarios() retornar uma lista que já está pronta e é mantida como um “cache” dentro do DAO, então nenhuma tentativa conseguirá removê-la pelo GC (já que o DAO terá uma referência para ela). Essa idéia é, de fato, muito ruim, pois quebra o encapsulamento do DAO e permite que objetos estranhos alterem a lista sem restrições. Mas apenas gostaria de lembrar que isso pode (infelizmente) acontecer.

    Grande abraço,
    Hugo.

Deixar uma Resposta