2009-05-12 20 views
95

Estaba navegando por algunos libros antiguos y encontré una copia de "Practical Java" de Peter Hagger. En la sección de rendimiento, hay una recomendación para establecer referencias de objeto a null cuando ya no sea necesario.¿El establecimiento de objetos Java a null hace algo más?

En Java, ¿las referencias de objeto de configuración a null mejoran el rendimiento o la eficiencia de la recolección de basura? Si es así, ¿en qué casos es esto un problema? Clases de contenedor? ¿Composición de objetos? ¿Clases internas anónimas?

Veo esto en el código con bastante frecuencia. ¿Es este consejo de programación obsoleto o sigue siendo útil?

+2

Haz clic aquí. En los tiempos de ejecución modernos, no debería ver ningún aumento significativo en el rendimiento o la huella de memoria. –

+12

@Jason, perfúlalo? Eso supone que perfilaré un conjunto lo suficientemente grande para obtener un conjunto de resultados lo suficientemente bueno como para responder a esto. Y que no elijo un conjunto de casos en los que la VM esté lo suficientemente optimizada como para enmascarar los problemas de rendimiento y gc. Es por eso que estoy preguntando esto aquí. Para tener una idea de los casos donde esto es un problema. – sal

+1

Duplicado de http://stackoverflow.com/questions/449409/does-assigning-objects-to-null-in-java-impact-garbage-collection. –

Respuesta

65

Depende un poco cuando estaba pensando en anular la referencia.

Si tiene una cadena de objetos A-> B-> C, una vez que A no es alcanzable, A, B y C serán elegibles para la recolección de basura (suponiendo que nada más se refiera a B o C). No es necesario, y nunca ha sido necesario, establecer explícitamente referencias A-> B o B-> C a nulas, por ejemplo.

Aparte de eso, la mayoría de las veces el problema no surge realmente, porque en realidad se trata de objetos en colecciones. En general, siempre debe pensar en eliminar objetos de las listas, mapas, etc. llamando al método apropiado remove().

el caso donde hay solía ser algunos consejos para establecer las referencias a nula fue específicamente en un largo alcance donde un objeto intensivo de la memoria dejó de ser utilizado parcialmente a través del alcance. Por ejemplo:

{ 
    BigObject obj = ... 
    doSomethingWith(obj); 
    obj = null;    <-- explicitly set to null 
    doSomethingElse(); 
} 

La lógica aquí es que debido a obj es todavía en su alcance, a continuación, sin la anulación explícita de la referencia, no se convierte en basura de colección hasta después de que el método doSomethingElse() completa. Y este es el consejo de que probablemente ya no sea válido para las JVM modernas: resulta que el compilador JIT puede funcionar en qué punto ya no se utiliza una referencia de objeto local determinada. campos

+1

La máquina puede optimizar las variables locales. Las variables de clase no pueden. He visto subprocesos de trabajo (en un grupo de subprocesos) no liberar sus objetos de estado después de gestionar la solicitud y fijar estos objetos en la memoria hasta que se le asignó una nueva tarea al subproceso de trabajo (que sobrescribió rápidamente los objetos de estado anterior con nuevos). Con grandes objetos de estado y cientos de subprocesos de trabajo (pensemos: gran servidor http), esto puede ser una gran cantidad de memoria retenida y copiada pero que nunca volverá a utilizarse. –

+0

Probablemente debería añadir: el consejo que doy más arriba es el consejo a seguir en general, asumiendo bibliotecas de buen comportamiento, una máquina virtual de buen comportamiento, etc. Si encuentra que tiene, por ejemplo, una biblioteca de grupo de subprocesos que cuelga de los objetos después de que un trabajo ha terminado, bueno ... eso es un error en dicha biblioteca de grupo de subprocesos que quizás podría solucionarse anulando una referencia de objeto, pero igualmente podría solucionarse utilizando una biblioteca de grupo de subprocesos con menos errores. No estoy seguro de que una falla así cambie los principios generales de diseño. –

24

No, no es un consejo obsoleto. Las referencias colgantes siguen siendo un problema, especialmente si está implementando, por ejemplo, un contenedor de matriz expandible (ArrayList o similar) utilizando una matriz preasignada. Los elementos más allá del tamaño "lógico" de la lista deben anularse, o de lo contrario no serán liberados.

Ver Effective Java 2nd ed, Item 6: Eliminar las referencias obsoletas a los objetos.

+0

¿Se trata de un problema de idioma o de implementación de VM? –

+4

Es un problema "semántico". Básicamente, debido a que ha preasignado una matriz, la VM lo ve.No sabe nada sobre el tamaño "lógico" de su contenedor. Supongamos que tiene una ArrayList de tamaño 10, respaldada por una matriz de 16 elementos. La máquina virtual no puede saber que los elementos 10..15 no se usan realmente; si esas ranuras tienen contenido, no serán liberadas. –

+0

¿qué pasa con las clases fuera del contenedor? En la composición de objetos donde el objeto interno no es desasignado por el objeto externo es. – sal

4

En entornos con memoria restrictiva (por ejemplo, teléfonos celulares) esto puede ser útil. Al establecer nulo, el objeto no necesita esperar la variable para salir del alcance que se va a generar.

Para la programación diaria, sin embargo, esta no debería ser la regla, excepto en casos especiales como el que citó Chris Jester-Young.

9

ejemplo, elementos de la matriz

Si hay una referencia a un objeto, que no pueden ser basura recogieron. Especialmente si ese objeto (y todo el gráfico detrás de él) es grande, solo hay una referencia que está deteniendo la recolección de basura, y esa referencia ya no es necesaria, esa es una situación desafortunada.

Los casos patológicos son el objeto que conserva una instancia insensible a todo el árbol DOM XML que se utilizó para configurarlo, el MBean no registrado o la única referencia a un objeto de una aplicación web no desplegada que impide un todo classloader de ser descargado.

De modo que, a menos que esté seguro de que el objeto que contiene la referencia en sí mismo será basura recogida de todos modos (o incluso entonces), debe anular todo lo que ya no necesita.

las variables con ámbito:

Si usted está considerando el establecimiento de una variable local para anular antes del final de su ámbito de aplicación, por lo que puede ser reclamado por el recolector de basura y para marcarlo como "no utilizable a partir de ahora ", deberías considerar ponerlo en un alcance más limitado en su lugar.

{ 
    BigObject obj = ... 
    doSomethingWith(obj); 
    obj = null;   // <-- explicitly set to null 
    doSomethingElse(); 
} 

convierte

{ 
    { 
    BigObject obj = ... 
    doSomethingWith(obj); 
    } //   <-- obj goes out of scope 
    doSomethingElse(); 
} 

alcances largas y planas son generalmente malas para la legibilidad del código, también. Tampoco es extraño que se introduzcan métodos privados para romper las cosas solo para ese propósito.

+0

Si se refiere a una referencia fuerte, sí, esto es cierto, pero no para todas las referencias. Las referencias débiles en Java pueden ser basura recolectada. –

0

En primer lugar, no significa nada de lo que está estableciendo un objeto nulo. Lo explico a continuación:

List list1=new ArrayList(); 
List list2=list1; 

En el segmento de código por encima de lo que estamos haciendo, en realidad estamos creando la referencia al objeto nombre de la variable de lista1 objeto ArrayList que se almacena en la memoria. Entonces list1 está refiriendo ese objeto y notando más que una variable. Y en la segunda línea de código estamos copiando la referencia de list1 en list2. Así que ahora vamos a volver a su pregunta si lo hago:

list1=null; 

que significa lista1 ya no se está refiriendo cualquier objeto que se almacena en la memoria de modo lista2 también no tener nada que hacer referencia. Así que si usted comprueba el tamaño de lista2:

list2.size(); //it gives you 0 

Así que aquí el concepto de recolector de basura llega el cual dice "que nada de que preocuparse liberar la memoria que se mantenga por el objeto, lo haré cuando me descubro que ya no se usará en el programa y que JVM me administrará ".

Espero que aclare el concepto.

0

Una de las razones para hacerlo es eliminar referencias de objetos obsoletas. Puedes leer el texto here.

Cuestiones relacionadas