Recolector de basura en java – establece un objeto nulo

Supongamos que hay un objeto Tree, con un objeto TreeNode raíz, y cada TreeNode tiene objetos leftNode y rightNode (por ejemplo, un objeto BinaryTree)

Si llamo:

myTree = null; 

¿Qué sucede realmente con los objetos TreeNode relacionados dentro del árbol? ¿También se recolectará basura, o tengo que establecer null todos los objetos relacionados dentro del objeto del árbol?

La recolección de basura en Java se realiza sobre la base de “accesibilidad”. El JLS define el término de la siguiente manera:

“Un objeto accesible es cualquier objeto al que se pueda acceder en cualquier cómputo potencial continuo desde cualquier hilo en vivo”.

Siempre que un objeto sea alcanzable * , no es elegible para la recolección de basura.

El JLS deja que la implementación de Java determine cómo determinar si un objeto puede ser accesible. Si la implementación no puede estar segura, es libre tratar un objeto teóricamente inalcanzable como accesible … y no recostackrlo. (De hecho, el JLS permite que una implementación no recolecte nada, ¡nunca! Sin embargo, ninguna implementación razonable haría eso).

En la práctica, la accesibilidad (conservadora) se calcula mediante el rastreo; mirando a lo que se puede llegar siguiendo las referencias que comienzan con las variables de clase (estáticas) y las variables locales en las stacks de subprocesos.


Esto es lo que esto significa para su pregunta:

Si llamo: myTree = null; ¿Qué sucede realmente con los objetos TreeNode relacionados dentro del árbol? ¿También se recolectará basura, o tengo que establecer null todos los objetos relacionados dentro del objeto del árbol?

Supongamos que myTree contiene la última referencia accesible a la raíz del árbol.

  1. Nada sucede inmediatamente.
  2. Si los nodos internos anteriormente solo podían alcanzarse a través del nodo raíz, ahora no están disponibles y son aptos para la recolección de elementos no utilizados. (En este caso, no es necesario asignar null a las referencias a los nodos internos).
  3. Sin embargo, si los nodos internos son accesibles a través de otras rutas, es de suponer que todavía pueden alcanzarse, y por lo tanto NO son elegibles para la recolección de basura. (En este caso, asignar un null a las referencias a los nodos internos es un error. Está desmantelando una estructura de datos que otra cosa podría tratar de usar más adelante).

Si myTree no contiene la última referencia accesible a la raíz del árbol, anular la referencia interna es un error por la misma razón que en el punto 3. anterior.


Entonces, ¿cuándo debes null cosas para ayudar al recolector de basura?

Los casos en los que debe preocuparse son cuando puede darse cuenta de que la referencia en alguna celda (variable local, de instancia o de clase, o elemento de matriz) no se volverá a utilizar, ¡pero el comstackdor y el tiempo de ejecución no pueden! Los casos se dividen en tres categorías:

  1. Referencias de objetos en variables de clase … que (por definición) nunca salen del scope.
  2. Referencias de objeto en variables locales que todavía están en el scope … pero no serán utilizadas. Por ejemplo:

      public List pigSquadron(boolean pigsMightFly) { List airbornePigs = new ArrayList(); while (...) { Pig piggy = new Pig(); ... if (pigsMightFly) { airbornePigs.add(piggy); } ... } return airbornePigs.size() > 0 ? airbornePigs : null; } 

    En lo anterior, sabemos que si pigsMightFly es falso, no se usará el objeto de la lista. Pero no se espera que ningún comstackdor de Java convencional lo descubra.

  3. Referencias de objeto en variables de instancia o en celdas de matriz donde las invariantes de estructura de datos significan que no se usarán. El ejemplo de stack de @ edalorzo es un ejemplo de esto.

Cabe señalar que el comstackdor / tiempo de ejecución a veces puede darse cuenta de que una variable dentro del scope está efectivamente muerta. Por ejemplo:

 public void method(...) { Object o = ... Object p = ... while (...) { // Do things to 'o' and 'p' } // No further references to 'o' // Do lots more things to 'p' } 

Algunos comstackdores / tiempos de ejecución de Java pueden detectar que ‘o’ no es necesario después de que termina el bucle, y tratan la variable como muerta.


* De hecho, de lo que estamos hablando aquí es de gran scope. El modelo de accesibilidad de GC es más complicado cuando se consideran referencias suaves, débiles y fantasmas. Sin embargo, estos no son relevantes para el caso de uso del PO.

myTree es solo una variable de referencia que anteriormente apuntaba a un objeto en el montón. Ahora lo está configurando para nulo. Si no tiene otra referencia a ese objeto, entonces ese objeto será elegible para la recolección de basura.

Para permitir que el recolector de basura elimine el objeto myTree simplemente haga una llamada a gc() después de que lo haya establecido como null

 myTree=null; System.gc(); 

Tenga en cuenta que el objeto se elimina solo cuando no hay otra referencia que lo señale.

Se recogerán basura a menos que tenga otras referencias (probablemente manuales). Si solo tiene una referencia al árbol, entonces sí, serán basura recolectada.

No puede establecer que un objeto sea null , solo una variable que pueda contener un puntero / referencia a este objeto. El objeto en sí no se ve afectado por esto. Pero si ahora no existen rutas de ningún hilo viviente (es decir, la variable local de cualquier método en ejecución) a su objeto, se recolectará basura, siempre y cuando la memoria sea necesaria. Esto se aplica a cualquier objeto, también a los que se hace referencia desde el objeto de árbol original.

Tenga en cuenta que para las variables locales normalmente no tiene que establecerlas en null si el método (o bloque) terminará pronto de todos modos.

En Java, no es necesario establecer explícitamente objetos en null para permitir que sean GC’d. Los objetos son elegibles para GC cuando no hay referencias (ignorando las clases java.lang.ref.* ).

Un objeto se recostack cuando no hay más referencias al mismo.

En su caso, los nodos a los que se refiere directamente el objeto referenciado formalmente por myTree (el nodo raíz) se recostackrán, y así sucesivamente.

Esto por supuesto no es el caso si tiene referencias sobresalientes a nodos fuera del árbol. Aquellos recibirán GC’d una vez que esas referencias salgan del scope (junto con cualquier cosa a la que se refieran)