Have you ever used PhantomReference in any project?

后端 未结 9 475
再見小時候
再見小時候 2020-11-29 17:02

The only thing I know about PhantomReference is,

  • If you use its get() method, it will always return null
9条回答
  •  臣服心动
    2020-11-29 17:45

    I used a PhantomReference in a unit test to verify that the code under test didn't keep unnessecary references to some object. (Original code)

    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
    {
    private final WeakReference weakReference;
    
    private FinalizationAwareObject(Object referent, ReferenceQueue referenceQueue)
    {
    super(checkNotNull(referent), referenceQueue);
    weakReference = new WeakReference(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());
    }
    }
    
    
    

    And the 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>");
        }
    }
    

    提交回复
    热议问题