Lo único que sé PhantomReference
es
- Si usa su
get()
método, siempre regresaránull
y no el objeto. ¿De qué sirve? - Al usar
PhantomReference
, te aseguras de que el objeto no se pueda resucitar delfinalize
método.
Pero, ¿de qué sirve este concepto / clase?
¿Ha usado esto alguna vez en alguno de sus proyectos o tiene algún ejemplo en el que deberíamos usarlo?
FakeReference
oNonReference
.Respuestas:
Usé
PhantomReference
s en un tipo de perfilador de memoria simplista y muy especializado para monitorear la creación y destrucción de objetos. Los necesitaba para realizar 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 poderosas y confiables y las características más nuevas de Java 5 como JMX o agentes y JVMTI también se pueden usar para eso.PhantomReference
s (siempre utilizados junto con la cola de referencia) son superiores a lofinalize
que tiene algunos problemas y, por lo tanto, deben evitarse. Principalmente hacer que los objetos sean accesibles nuevamente. Esto podría evitarse con el modismo guardián del finalizador (-> leer más en 'Java efectivo'). Así que también son los nuevos finalizados .Además,
PhantomReference
sY como psd escribió primero, Roedy Green tiene un buen resumen de referencias .
fuente
Una explicación general de la tabla cortada en cubitos , del Glosario de Java.
Que por supuesto coincide con la documentación de PhantomReference :
Y por último, pero no 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 amar OutOfMemoryError) .
Codificación feliz. (Pero para responder a la pregunta, solo he usado WeakReferences).
fuente
Gran explicación del uso de Phantom Reference:
fuente
Encontré un caso de uso práctico y útil
PhantomReference
que estáorg.apache.commons.io.FileCleaningTracker
en el proyecto commons-io.FileCleaningTracker
eliminará el archivo físico cuando su objeto marcador sea recolectado como basura.Algo a tener en cuenta es la
Tracker
clase que amplía laPhantomReference
clase.fuente
¡ESTO DEBE SER OBSOLETO CON JAVA 9!
¡Úselo en su
java.util.Cleaner
lugar! (Osun.misc.Cleaner
en JRE más antiguo)Publicación original:
Descubrí que el uso de PhantomReferences tiene casi la misma cantidad de trampas que los métodos de finalizador (pero 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 que se ejecutarán después de que se haya eliminado el objeto. Puede registrar las devoluciones de llamada para 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 el cierre automático, haciendo aproximadamente lo mismo que el anterior:
this.registerAutoClose(this.resource);
Para responder tu pregunta:
No puedes limpiar algo que no existe. Pero podría haber tenido recursos que aún existen y deben limpiarse para poder eliminarlos.
No es necesariamente para hacer nada con ningún efecto que no sea depurar / registrar. O quizás por estadísticas. Lo veo más como un servicio de notificación del GC. También podría querer usarlo para eliminar 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 que las conexiones de la base de datos deben cerrarse, pero no veo cómo esto es una buena idea ya que no podría trabajar con transacciones. Un marco de aplicación proporcionará una solución mucho mejor para eso.
Lo uso principalmente solo para registrar. Entonces puedo rastrear los elementos eliminados y ver cómo funciona GC y cómo se puede modificar. No ejecutaría ningún código crítico de esta manera. Si es necesario cerrar algo, debe hacerlo en una declaración try-with-resource-statement. Y lo uso en pruebas unitarias, para asegurarme de que no tengo pérdidas de memoria. De la misma manera que lo hace jontejj. Pero mi solución es un poco más general.
fuente
Usé una PhantomReference en una prueba unitaria para verificar que el código bajo prueba no guardaba referencias desagradables 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 prueba :
@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>"); } }
fuente
Es común usarlo
WeakReference
dondePhantomReference
sea más apropiado. Esto evita ciertos problemas de poder resucitar objetos despuésWeakReference
de que el recolector de basura haya borrado / puesto en cola. Por lo general, la diferencia no importa porque la gente no juega a ser tontos.El uso
PhantomReference
tiende a ser un poco más intrusivo porque no se puede fingir que elget
método funciona. No puede, por ejemplo, escribir unPhantom[Identity]HashMap
.fuente
weakref.get
podría volvernull
, y luego, más tarde, todavía puede devolver el obj?finalize
no recrea el objeto como tal. Puede hacer que el objeto sea fácilmente accesible de nuevo después de unWeakReference
retornonull
deget
y se pone en cola. / (user166390: como en un mapa con clave en el objetivo de la referencia, como loWeakHashMap
hace, no un mapa de identidad de referencias, lo cual está bien)Los métodos útiles para llamar (en lugar de
get()
) seríanisEnqueued()
oreferenceQueue.remove()
. Llamaría a estos métodos para realizar alguna acción que debe tener lugar en la ronda final de recolección de basura del objeto.La primera vez es cuando el objeto tiene su
finalize()
método llamado, por lo que también podría poner ganchos de cierre allí. Sin embargo, como han dicho otros, probablemente hay formas más seguras de realizar la limpieza o cualquier acción que deba realizarse antes y después de la recolección de basura o, más en general, al final de la vida útil del objeto.fuente
Encontré otro uso práctico de
PhantomReferences
en la clase LeakDetector de Jetty.Jetty usa
LeakDetector
class para detectar si el código de cliente adquiere un recurso pero nunca lo libera y laLeakDetector
clase usa elPhantomReferences
para este propósito.fuente