overview español java reference

java - español - ¿Alguna vez ha usado PhantomReference en algún proyecto?



java documentation (8)

Lo único que sé sobre PhantomReference es,

  • Si usa su método get() , siempre devolverá null y no el objeto. ¿De qué sirve?
  • Al utilizar PhantomReference , asegúrate de que el objeto no pueda resucitar del método de finalize .

Pero, ¿cuál es el uso de este concepto / clase?

¿Alguna vez ha usado esto en alguno de sus proyectos o tiene algún ejemplo donde deberíamos usar esto?


si usa su método get (), siempre devolverá null, y no el objeto. [entonces cuál es el uso de eso]

Los métodos útiles para llamar (en lugar de get() ) serían isEnqueued() o referenceQueue.remove() . Llamaría a estos métodos para realizar alguna acción que deba llevarse a cabo en la ronda final de recolección de basura del objeto.

La primera vez es cuando el objeto tiene su método finalize() llamado, por lo que podría poner ganchos de cierre allí también. Sin embargo, como han indicado otros, probablemente haya formas más seguras de realizar la limpieza o cualquier acción que deba llevarse a cabo antes y después de la recolección de basura o, más en general, al final de la vida útil del objeto.


Encontré un caso de uso práctico y útil de PhantomReference que es org.apache.commons.io.FileCleaningTracker en el proyecto commons-io. FileCleaningTracker eliminará el archivo físico cuando su objeto marcador sea basura.
Algo a tener en cuenta es la clase Tracker , que amplía la clase PhantomReference .


Es común usar WeakReference donde PhantomReference es más apropiado. Esto evita ciertos problemas de poder resucitar objetos después de que el recopilador de basura haya borrado / en WeakReference una WeakReference . Por lo general, la diferencia no importa porque la gente no está jugando a tontos.

Usar PhantomReference tiende a ser un poco más intrusivo porque no puedes pretender que el método get funciona. No puede, por ejemplo, escribir un Phantom[Identity]HashMap .


Una explicación general de la tabla en cubos , del Glosario de Java.

Lo cual, por supuesto, coincide con la documentación de PhantomReference :

Objetos de referencia fantasma, que se ponen en cola después de que el recopilador determine que sus referentes pueden recuperarse. Las referencias ficticias se utilizan con mayor frecuencia para programar acciones de limpieza premortem de una manera más flexible que la que es posible con el mecanismo de finalización de Java.

Y por último, pero no por ello menos importante, todos los detalles sangrientos ( esta es una buena lectura ): objetos de referencia de Java (o cómo aprendí a dejar de preocuparme y me encanta OutOfMemoryError) .

Feliz codificación. (Pero para responder a la pregunta, solo he usado WeakReferences).


Utilicé PhantomReference s en un tipo de perfilador de memoria simplista y muy especializado para monitorizar la creación y destrucción de objetos. Los necesitaba para hacer un seguimiento de la destrucción. Pero el enfoque está desactualizado. (Fue escrito en 2004 con el objetivo de J2SE 1.4.) Las herramientas de creación de perfiles profesionales son mucho más potentes y confiables, y las funciones más nuevas de Java 5, como JMX o agentes, y JVMTI también se pueden usar para eso.

PhantomReference s (siempre utilizado junto con la cola de referencia) son superiores a la finalize que tiene algunos problemas y, por lo tanto, deben evitarse. Principalmente haciendo que los objetos sean alcanzables nuevamente. Esto podría evitarse con la expresión del guardián del finalizador (-> leer más en ''Java efectivo''). Entonces ellos también son el nuevo finalizador .

Además, PhantomReference s

le permiten determinar exactamente cuándo se eliminó un objeto de la memoria. De hecho, son la única forma de determinar eso. Esto generalmente no es tan útil, pero puede ser útil en ciertas circunstancias muy específicas, como la manipulación de imágenes grandes: si está seguro de que una imagen debe ser recogida de basura, puede esperar hasta que esté realmente antes de intentar cargar la siguiente imagen y, por lo tanto, hacen que el temido OutOfMemoryError sea menos probable. (Citado de enicholas )

Y como psd escribió primero, Roedy Green tiene un buen resumen de referencias .


Utilicé una PhantomReference en una prueba unitaria para verificar que el código bajo prueba no guardara referencias exclusivas a algún objeto. ( Código original )

import static com.google.common.base.Preconditions.checkNotNull; import static org.fest.assertions.Assertions.assertThat; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import com.google.common.testing.GcFinalization; /** * Helps to test for memory leaks */ public final class MemoryTester { private MemoryTester() { } /** * A simple {@link PhantomReference} that can be used to assert that all references to it is * gone. */ public static final class FinalizationAwareObject extends PhantomReference<Object> { private final WeakReference<Object> weakReference; private FinalizationAwareObject(Object referent, ReferenceQueue<Object> referenceQueue) { super(checkNotNull(referent), referenceQueue); weakReference = new WeakReference<Object>(referent, referenceQueue); } /** * Runs a full {@link System#gc() GC} and asserts that the reference has been released * afterwards */ public void assertThatNoMoreReferencesToReferentIsKept() { String leakedObjectDescription = String.valueOf(weakReference.get()); GcFinalization.awaitFullGc(); assertThat(isEnqueued()).as("Object: " + leakedObjectDescription + " was leaked").isTrue(); } } /** * Creates a {@link FinalizationAwareObject} that will know if {@code referenceToKeepTrackOff} * has been garbage collected. Call * {@link FinalizationAwareObject#assertThatNoMoreReferencesToReferentIsKept()} when you expect * all references to {@code referenceToKeepTrackOff} be gone. */ public static FinalizationAwareObject createFinalizationAwareObject(Object referenceToKeepTrackOff) { return new FinalizationAwareObject(referenceToKeepTrackOff, new ReferenceQueue<Object>()); } }

Y la test :

@Test public void testThatHoldingOnToAnObjectIsTreatedAsALeak() throws Exception { Object holdMeTight = new String("Hold-me-tight"); FinalizationAwareObject finalizationAwareObject = MemoryTester.createFinalizationAwareObject(holdMeTight); try { finalizationAwareObject.assertThatNoMoreReferencesToReferentIsKept(); fail("holdMeTight was held but memory leak tester did not discover it"); } catch(AssertionError expected) { assertThat(expected).hasMessage("[Object: Hold-me-tight was leaked] expected:<[tru]e> but was:<[fals]e>"); } }


Gran explicación del uso de la referencia Phantom:

Las referencias ficticias son una forma segura de saber que un objeto ha sido eliminado de la memoria. Por ejemplo, considere una aplicación que se ocupa de imágenes de gran tamaño. Supongamos que queremos cargar una imagen grande en la memoria cuando la imagen grande ya está en la memoria y está lista para la basura recolectada. En tal caso, queremos esperar hasta que se recopile la imagen anterior antes de cargar una nueva. Aquí, la referencia fantasma es una opción flexible y segura para elegir. La referencia de la imagen anterior se colocará en cola en la ReferenceQueue una vez que se finalice el objeto de imagen anterior. Después de recibir esa referencia, podemos cargar la nueva imagen en la memoria.


¡ESTO DEBE SER OBSOLETO CON JAVA 9!
¡Usa java.util.Cleaner lugar! (O sun.misc.Cleaner en JRE más viejo)

Publicación original:

Descubrí que el uso de PhantomReferences tiene casi la misma cantidad de dificultades que los métodos de finalización (pero hay menos problemas una vez que lo haces bien). He escrito una pequeña solución (un marco muy pequeño para usar PhantomReferences) para Java 8. Permite usar expresiones lambda como devoluciones de llamada para ejecutar después de que el objeto ha sido eliminado. Puede registrar las devoluciones de llamada para los recursos internos que deben cerrarse. Con esto, he encontrado una solución que me funciona, ya que la hace mucho más práctica.

https://github.com/claudemartin/java-cleanup

Aquí hay un pequeño ejemplo para mostrar cómo se registra una devolución de llamada:

class Foo implements Cleanup { //... public Foo() { //... this.registerCleanup((value) -> { try { // ''value'' is ''this.resource'' value.close(); } catch (Exception e) { logger.warning("closing resource failed", e); } }, this.resource); }

Y luego está el método aún más simple para cerrar automáticamente, haciendo casi lo mismo que el anterior:

this.registerAutoClose(this.resource);

Para responder tu pregunta:

[entonces cuál es el uso de eso]

No puedes limpiar algo que no existe. Pero podría haber tenido recursos que aún existen y necesitan ser limpiados para que puedan ser eliminados.

Pero, ¿cuál es el uso de este concepto / clase?

No es necesariamente hacer nada con otro efecto que no sea la eliminación de errores / registro. O tal vez para las estadísticas. Lo veo más como un servicio de notificación del GC. También podría querer usarlo para eliminar los datos agregados que se vuelven irrelevantes una vez que se elimina el objeto (pero probablemente haya mejores soluciones para eso). Los ejemplos a menudo mencionan conexiones de bases de datos que se cerrarán, pero no veo cómo es una buena idea, ya que no se puede trabajar con transacciones. Un marco de aplicación proporcionará una solución mucho mejor para eso.

¿Alguna vez has usado esto en alguno de tus proyectos, o tienes algún ejemplo donde deberíamos usar esto? ¿O es este concepto hecho solo para el punto de vista de la entrevista;)

Lo uso principalmente solo para iniciar sesión. Así que puedo rastrear los elementos eliminados y ver cómo funciona GC y se puede ajustar. No ejecutaría ningún código crítico de esta manera. Si algo necesita ser cerrado, entonces debe hacerse en una declaración try-with-resource. Y lo uso en pruebas unitarias, para asegurarme de que no tenga ninguna pérdida de memoria. De la misma manera que jontejj lo hace. Pero mi solución es un poco más general.