JDK-8024421 : (ref) GC should clear PhantomReference
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • Submitted: 2013-05-31
  • Updated: 2015-04-29
  • Resolved: 2013-09-06
Related Reports
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
Phantom references should be cleared by the garbage collector as they are enqueued.

JUSTIFICATION :
Keeping phantom reachable objects in heap has some drawbacks:
1. At least 2 GC are required in order to reclaim them, even in case when application code pulls references from reference queue and clears them promptly.
2. GC pauses are increased since phantom reachable objects are still to be marked.

On the other hand, benefits are not obvious. Its referent cannot be used since it's not accessible.


ACTUAL -
attached test fails with OOM:
Exception in thread  " main "  java.lang.OutOfMemoryError: Java heap space
at test.RefHugeTest.newHugeObject(RefHugeTest.java:34)
at test.RefHugeTest.main(RefHugeTest.java:13)


---------- BEGIN SOURCE ----------
package test;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class RefHugeTest {
    public static void main(String[] args) throws IllegalArgumentException, InterruptedException {
        ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
        Reference<Object> reference = newReference(newHugeObject(), queue);
        Object huge = newHugeObject();
        drainReferences(queue);
        System.out.println( " ok " );
    }

    private static void drainReferences(ReferenceQueue<Object> queue) {
        Reference<?> ref;
        while ((ref = queue.poll()) != null) {
            ref.clear();
        }
    }

    private static <T> Reference<T> newReference(T referent, ReferenceQueue<? super T> queue) {
        Reference<T> reference = new PhantomReference<T>(referent, queue);
//        Reference<T> reference = new SoftReference<T>(referent, queue);
//        Reference<T> reference = new WeakReference<T>(referent, queue);
        return reference;
    }

    private static Object newHugeObject() {
        int size = (int) (Runtime.getRuntime().maxMemory() * 2 / 3);
        return new byte[size];
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
use weak references and avoid finalizers.
Comments
The PhantomReference API spec (http://docs.oracle.com/javase/7/docs/api/java/lang/ref/PhantomReference.html) prohibits it: Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
06-09-2013