Objetos elegíveis para garbage collection

Esta pergunta foi tirada de Kathy Sierra SCJP 1.6 . Quantos objects são elegíveis para coletas de lixo?

De acordo com a resposta de Kathy Sierra, é C Isso significa que dois objects são elegíveis para garbage collection. Eu dei a explicação da resposta. Mas por que c3 não é elegível para garbage collection (GC)?

 class CardBoard { Short story = 200; CardBoard go(CardBoard cb) { cb = null; return cb; } public static void main(String[] args) { CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); CardBoard c3 = c1.go(c2); c1 = null; // Do stuff } } 

Quando // Do stuff é alcançado, quantos objects são elegíveis para GC?

  • R: 0
  • B: 1
  • C: 2
  • D: Compilação falha
  • E: não é possível saber
  • F: Uma exceção é lançada no tempo de execução

Responda:

  • C está correto. Apenas um object CardBoard (c1) é elegível, mas possui um object Short wrapper associado que também é elegível.
  • A, B, D, E e F estão incorretos com base no acima. (Objetivo 7.4)

Nenhum object já existiu para o qual c3 aponta. O construtor foi chamado apenas duas vezes, dois objects, cada um apontado por c1 e c2 . c3 é apenas uma referência, que nunca recebeu nada além do ponteiro nulo.

A referência c3 , que atualmente aponta para null, não sairá do escopo e será removida da pilha até que a chave de fechamento no final do método principal seja cruzada.

O object originalmente atribuído a c1 é inacessível porque a referência c1 foi definida como nula, mas a referência c2 não foi alterada, portanto, o object atribuído a ela ainda pode ser alcançado a partir desse escopo por meio da referência c2 .

Vamos dividir isso linha por linha:

 CardBoard c1 = new CardBoard(); 

Agora temos dois objects, o CardBoard c1 aponta para e o Short c1.story . Tampouco está disponível para GC como pontos c1 no CardBoard e a variável story dos pontos CardBoard no Short

 CardBoard c2 = new CardBoard(); 

Similar ao anterior, agora temos quatro objects, nenhum dos quais está disponível para o GC.

 CardBoard c3 = c1.go(c2); 

Invocamos o método ir no CardBoard apontado por c1 , passando o valor de c2 que é uma referência a um object CardBoard . Nós nulo o parâmetro, mas Java é passado por valor, o que significa que a própria variável c2 não é afetada. Em seguida, retornamos o parâmetro nulled. c3 é null , c1 e c2 não são afetados. Ainda temos 4 objects, nenhum dos quais pode ser GC.

 c1 = null; 

Nós nulo c1 . O object CardBoard que c1 apontou anteriormente agora não tem nada apontado para ele, e pode ser GC’d. Como a variável de story dentro do object CardBoard é a única que aponta para o Short , e como esse object CardBoard é elegível para o GC, o Short também se torna elegível para o GC. Isso nos dá 4 objects, 2 dos quais podem ser GC’d. Os objects elegíveis para GC são aqueles anteriormente referenciados por c1 e c1.story .

c3 é null , portanto, não há claramente nenhum object qualificado para garbage collection.

Note que apenas dois objects CardBoard são criados, os dois nestas linhas:

 CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); 

e após o malabarismo de referência, apenas um deles é sem referências.

A resposta formalmente correta é que não sabemos. E a razão pela qual não sabemos é esta linha:

 Short story = 200; 

Isso compila para o seguinte código de byte:

 CardBoard(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: aload_0 5: sipush 200 8: invokestatic #2 // Method java/lang/Short.valueOf:(S)Ljava/lang/Short; 11: putfield #3 // Field story:Ljava/lang/Short; 14: return 

A linha 8 é a chave aqui, Short.valueOf() , que retorna um equivalente em checkbox do primitivo 200 . Vamos ver o Javadoc de Short.valueOf() :

Esse método sempre armazenará em cache valores no intervalo de -128 a 127, inclusive, e poderá armazenar em cache outros valores fora desse intervalo.

200 está fora do intervalo “deve cache” e, portanto, cai em “pode ​​armazenar em cache”. Se estiver em cache, o valor da story não será elegível para o GC quando a instância CardBoard estiver CardBoard . Se não estiver em cache, a story ficará inacessível e, portanto, será exibida.

Para tornar a questão não ambígua (e a resposta proposta correta), o código deve ser alterado assim:

 Short story = new Short(200); 

Update: O 1.6 Javadoc para Short.valueOf() é bastante mais enigmático que a versão 1.8 que citei, mas a mesma lógica se aplica: não há como saber apenas olhando para o código se uma instância nova ou em cache de Short será Ser devolvido.

Se você perceber que há apenas dois objects criados no código. c3 nunca é inicializado para um object, é uma referência nula. Portanto, apenas um “object” é elegível para garbage collection.