2010-01-18 14 views
12

Una pequeña pregunta sobre el rendimiento en una aplicación web Java.Java Collections y Garbage Collector

Supongamos que tengo un List<Rubrique>listRubriques con diez objetos Rubrique.

Un Rubrique contiene una lista de productos (List<product>listProducts) y una lista de clientes (List<Client>listClients).

¿Qué ocurre exactamente en la memoria si hago esto:

listRubriques.clear(); listRubriques = null; 

Mi punto de vista sería que, ya listRubriques está vacía, todos mis objetos previamente referenciados por esta lista (incluyendo listProducts y listClients) será basura recogida muy pronto. Pero ya que la colección en Java son un poco complicado y ya que tengo problemas de rendimiento bastante con mi aplicación que estoy haciendo la pregunta :)

edición: vamos a suponer ahora que mi objeto de cliente contiene un List<Client>. Por lo tanto, tengo una especie de referencia circular entre mis objetos. ¿Qué pasaría si mi listRubrique está configurado en null? Esta vez, mi punto de vista sería que mis objetos de Cliente se volverán "inalcanzables" y podría crear una pérdida de memoria?

Respuesta

14

La implementación real de Sun para Java copia de vez en cuando todos los objetos referenciados/vivos. El espacio desde el que se copió puede utilizarse nuevamente para la asignación de memoria.

Dicho esto, sus ejemplos dañan realmente el rendimiento. listRubriques.clear() es innecesario (salvo que se haga referencia a alguna otra parte), porque todo lo que hace referencia listRubrique es basura en el momento listRubriques ya no se hace referencia. listRubriques = null también puede ser innecesario si la variable listRubriques queda fuera del alcance después (posiblemente porque es una variable local y el método termina aquí).

No solo no se necesita la llamada para borrar, ya que el acceso claro a la memoria del objeto que luego no está en uso, se accede al objeto y los procesadores modernos lo colocarán en su caché. Entonces, un objeto muerto va explícitamente al caché del procesador; algunos datos posiblemente más útiles se sobrescribirán para esa operación.

This article es una buena referencia para obtener más información sobre el recolector de basura de Java.

EDITAR: Para reaccionar en la edición en la pregunta: el recolector de basura (la aplicación utilizada por Sun al menos) es a partir de algunas referencias de raíz y copia todos los objetos que puede llegar a partir de esta referencia y que hace referencia los objetos copiados. Por lo tanto, los objetos de referencia circular son basura, ya que ninguna referencia "externa" los señala y la memoria se recuperará en la recolección de elementos no utilizados.

+0

Cuidado: la primera oración describe la implementación actual de Sun JVM. No es una afirmación que sea cierta acerca de Java en general. Sin embargo, el resto de la respuesta parece ser aplicable en general. –

+0

Gracias por la pista, cambié la primera oración. – Mnementh

3

Si usted tiene:

listRubriques = null; 

y no hay ningún otro objeto que referencie a listRubriques o sus objetos que contienen, es elegibles para la recolección de basura. Pero no hay garantía de cuándo la JVM realmente ejecutará la recolección de basura en ella y liberará la memoria.Puede llamar:

System.gc(); 

recomendar a la JVM que usted piensa que están colección de basura en este momento es una buena idea. Pero incluso entonces, no hay garantía.

También tener

listRubriques.clear(); 

antes de listRubriques a null no es necesario.

EDITAR: Para responder a su pregunta sobre referencias circulares, JVM son lo suficientemente inteligente como para darse cuenta de que todo el gráfico de objetos esté desconectado de cualquier código que se ejecuta de forma activa y la JVM determinar correctamente que todos ellos son aptos para reciclaje. Esto siempre ha sido cierto incluso en los malos tiempos del recuento de referencias. Las JVM modernas son más rápidas y eficientes. Pero no son basura recolectando más objetos que las JVM antiguas.

+0

Con respecto al claro antes del nulo lo hice simplemente para asegurarme de que mi objeto ya no tenga más referencias. Pero estoy bien, es una doble verificación inútil. Leí ese System.gc(); fue útil en versiones antiguas de Java, pero hoy se ignora por completo, ¿no? – Anth0

+0

@ Anth0: No he oído eso y los documentos J2SE para Java 6 no mencionan nada de eso (http://java.sun.com/javase/6/docs/api/java/lang/System.html #gc()). Para una portabilidad máxima, es mejor no hacer suposiciones sobre la implementación de JVM en la que se ejecutará su aplicación. Eche un vistazo a este artículo de Sun sobre la verdad sobre la recolección de basura: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html – Asaph

+0

Invocar System.gc() generalmente es otorgado por el más reciente VMs también, aunque no garantizado. Si solicita que se ejecute el GC, aunque no es necesario, puede crear un problema de rendimiento y no resolverlo. – jarnbjo

1

"Muy pronto" es una especificación bastante vaga, pero es probable que el recolector de basura no sea tan rápido como parece esperar. Cuando los objetos realmente serán recolectados depende mucho de la configuración del GC y de la carga de su servidor, pero puede llevar algo de tiempo y si su máquina virtual tiene suficiente pila disponible y otras cosas que hacer, los objetos no se recolectarán "muy pronto". .

La única situación en la que la especificación de VM garantiza que se ejecutará el GC, es cuando en algún momento se lanzará un OutOfMemoryError. Antes de lanzar un OutOfMemoryError, la VM está obligada a intentar al menos recopilar tantas instancias de objetos elegibles, que la solicitud de asignación de memoria relevante puede tener éxito (pero aún no se garantiza que todas las instancias elegibles se recopilen).

Cuestiones relacionadas