Java Reference Types
References
[1] https://blog.csdn.net/u011974987/article/details/46866229
Java provides two different types/classes of Reference Objects: strong and weak. Weak Reference Objects can be further divided into soft and phantom.
Strong Reference
StringBuilder builder = new StringBuilder();
This is the default type/class of Reference Object, if not differently specified: builder
is a strong Reference Object. This kind of reference makes the referenced object not eligible for GC. That is, whenever an object is referenced by a chain of strong Reference Objects, it cannot be garbage collected.
Weak Reference
WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);
Weak Reference Objects are not the default type/class of Reference Object and to be used they should be explicitly specified like in the above example. This kind of reference makes the reference object eligible for GC. That is, in case the only reference reachable for the StringBuilder object in memory is, actually, the weak reference, then the GC is allowed to garbage collect the StringBuilder object. When an object in memory is reachable only by Weak Reference Objects, it becomes automatically eligible for GC.
Soft Reference
Garbage collector can collect an object if only weak references are pointing towards it and they are eagerly collected, on the other hand Objects with SoftReference are collected when JVM absolutely needs memory.
Phantom Reference
Object which only has Phantom reference pointing them can be collected whenever Garbage Collector likes it.
Useful Classes
WeakHashMap
Hash table based implementation of the Map interface, with weak keys. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.
ReferenceQueue
If the garbage collector discovers an object that is weakly reachable, the following occurs:
- The WeakReference object's referent field is set to null, thereby making it not refer to the heap object any longer.
- The heap object that had been referenced by the WeakReference is declared finalizable.
- The WeakReference object is added to its ReferenceQueue. Then the heap object's finalize() method is run and its memory freed.
When creating non-strong reference objects we have the option of passing a reference queue as a part of the Reference constructor. As seen from the above explanation, this reference queue is a way for the GC to inform the program that a certain object is no longer reachable.
Example
import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; public class Test { public static void main(String[] args) throws InterruptedException { SavePoint savePoint = new SavePoint("Random"); // a strong object ReferenceQueue<SavePoint> savepointQ = new ReferenceQueue<SavePoint>();// the ReferenceQueue WeakReference<SavePoint> savePointWRefernce = new WeakReference<SavePoint>(savePoint, savepointQ); System.out.println("SavePoint created as a weak ref " + savePointWRefernce); Runtime.getRuntime().gc(); System.out.println("Any weak references in Q ? " + (savepointQ.poll() != null)); savePoint = null; // the only strong reference has been removed. The heap // object is now only weakly reachable System.out.println("Now to call gc..."); Runtime.getRuntime().gc(); // the object will be cleared here - finalize will be called. System.out.println("Any weak references in Q ? " + (savepointQ.remove() != null)); System.out.println("Does the weak reference still hold the heap object ? " + (savePointWRefernce.get() != null)); System.out.println("Is the weak reference added to the ReferenceQ ? " + (savePointWRefernce.isEnqueued())); } } class SavePoint { public SavePoint(String value) { } }
The program :
- Creates a strong reference and adds it to a Weak reference savePointWRefernce. The object in memory is now referenced by a strong reference and a weak reference - hence strongly reachable.
- The first call to garbage collector will not clear our savepoint object as it is a strong reference. Hence the poll method of the referenceQ will return null. (poll method is non - blocking it checks and returns immediately.)
- The savePoint reference variable is set to null. Our heap object is now referenced only by the weak reference - hence it is weakly reachable.
- The second gc call will now locate the object, executes its finalize method and mark this object to be freed. Theobject is also added to the ReferenceQ.
- A call to the remove method of the ReferenceQ will return the object. remove is a blocking method. it will wait till an object has been made available in the Queue. (poll method might not work as the recycling process is happening on a separate thread.)
As seen once the object was ready to be released it was added to the reference queue. So the reference queue is like a callback to our java program, telling us that a particular object is released from its reference and is not available to our code anymore.
As seen from above the Reference queue actually holds within it the WeakReference which lost its heap object to clean up. The WeakReference does not have any association to the memory object. The get call above returns null. Unlike with finalize when we can make the object alive again, with the ReferenceQ there is no way to reach the released java object. Reference Queues are just for References that got freed by garbage collection. They cannot be used to make alive our objects again. They can only be used to notify our code about the loss of memory objects referred to by these non- strong references.
弱引用 vs 虚引用
gc收集弱可及对象的执行过程和软可及一样,只是gc不会根据内存情况来决定是不是收集该对象。
如果你希望能随时取得某对象的信息,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来记住此对象,而不是用一般的 reference。
这类的技巧,在设计 Optimizer 或 Debugger 这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以 影响此对象的垃圾收集。在此例中,透过 get() 可以取得此 Reference 的所指到的对象,如果返回值为 null 的话,代表此对象已经被清除。
if (wr.get()==null) { System.out.println("obj 已经被清除了 "); } else { System.out.println("obj 尚未被清除,其信息是 "+obj.toString()); }
PhantomRefrence(虚引用)建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null.先看一下和gc交互的过程在说一下他的作用.