Soft,Weak,Phantom Reference
java.lang.ref.Reference<T> 是他们共同的父类, 提供通过 Reference.get()间接引用T对象的功能. 而Reference内部对T的引用(T referent),不同于一般引用,GC会对其特殊处理: 一般来说 当一个对象的所有引用都是Reference引用时, GC会回收它, 但具体回收的策略和时间, GC会根据具体的实现类区分:
WeakReference:当GC检测到所有引用都是WeakReference时会依次做: 1,原子的删除所有此Reference的引用及级联reference, 之后get()返回null. 2.标识这些对象为finalizable. 3. ReferenceQueue.enqueue. 主要的应用是 WeakHashMap将 Entry继承WeakReference, 并将key赋予WeakReference.referent. 由其他调用(put(),size()等)触发清除: poll ReferenceQueue中的Entry将其移除.
SoftReference: 和Weak的区别在于, 只有当内存满的情况下才会尝试回收.
PhantomReference: Phantom和Weak和Soft不同, 首先,PhantomReference get()永远返回 null。另外,调用enqueue的时机不同,Weak是在finalize()和GC前, Phantom是在真正内存擦除后。这样会更安全的做一些善后清理(post-mortem)工作,比如 DirectByteBuffer的内存释放.
考虑一种情况,如果Object重写了finalize(), 这个对象有可能被复活,比如给一个Strong ref, 所以重写finalize的object需要至少2个GC周期来彻底回收。此时WeakReference会在第一个GC之前enqueue,而如果是PhantomReference则会在彻底回收之后才enqueue.
所以当PhantomReference被enqueue到ReferenceQueue时,就说明object确实被彻底回收了(reclaimed), 利用这一点,可以放心的做一些cleanup的工作,而不用担心finalize()复活对象。这可以看做是 一种更灵活的替代Java finalize()的机制。 典型的应用就是 DirectByteBuffer, 因为不存在被复活的风险,所以堆外内存的释放是通过PhantomReference实现的.
https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references
https://en.wikipedia.org/wiki/Phantom_reference