Please note the original source, thank you!

background

Some time ago, WHEN I saw various references in Java being discussed in the group, I couldn’t help thinking about them. I found that MY understanding of them was only superficial, and I was not familiar with their implementation principle and recycling mechanism, which made me feel uneasy.

After the snow, the magic is colder, but Java avenue, the more down the more yong.

A simple HashMap is a crude version of a cache. If you keep adding data to it, the JVM will get OOM sooner or later.

Four types of references

At the Java level, there are four types of references: strong references, soft references, weak references, and virtual references. As you can see from their names, these references have a life cycle from strong to weak.

Why at the Java level, because in addition to these four references, there are two others. It’s just that these four are within reach of the code, while the other two are almost invisible.

Strong reference

Strong references are the most commonly used references. 99% of code is Strong references, and many people are exposed to Strong references, such as the following:

Object o = new Object()

This situation is common, and additional references may only be needed when writing middleware framework code.

If an object has a strong reference relationship with GC Root, it is better to throw an OOM exception and terminate the program when GC is out of memory than to reclaim the object.

Conversely, an object that does not have a strong reference to the GC Root may be reclaimed (because there may be other references). If there are no references, the object will be reclaimed after GC.

Soft references

Soft references, which describe less important objects, have a feature that ensures that they stay in the JVM for as long as possible and are only reclaimed after multiple GC sessions when they run out of memory, making them particularly useful for caching.

Object reference = new MyObject(); System.out.println(reference); Reference root = new SoftReference(reference); reference = null; // MyObject only has a soft reference to system.gc (); System.out.println(root.get());Copy the code

After GC is forced, the object referenced by SoftReference is not reclaimed. At what point in time will the SoftReference object be reclaimed? Those of you who are interested can imagine.

A weak reference

Weak references, which have a shorter lifetime than soft references, will be reclaimed when GC occurs if an object is detected to have only Weak references, regardless of whether the current memory is sufficient.

Sounds a little dry. Let’s quench our thirst with a code.

Object reference = new MyObject(); System.out.println(reference); Reference root = new WeakReference(reference); reference = null; // MyObject has only weak references to system.gc (); System.out.println(root.get());Copy the code

After GC occurs, root.get() returns null, indicating that the object has been collected.

In WeakHashMap of JDK, WeakReference is well applied, where Entry inherits WeakReference. If an Entry object does not have a strong reference pointing to key, WeakHashMap will automatically delete the relevant Entry after GC.

Phantom reference

The main difference between Phantom Reference and the previous two is that its get method always returns NULL.

Oddly, what is the use of a reference that returns NULL?

The use of virtual references is very narrow, and in the JDK it is currently only known to occur when requesting out-of-heap memory. When applying for out-of-heap memory, a corresponding Cleaner object will be created in the JVM heap. This Cleaner class inherits PhantomReference. When DirectByteBuffer object is collected, the corresponding Cleaner object’s clean method can be executed and some follow-up work can be done. This is to free the out-of-heap memory.

Since the get method of a virtual reference can’t get the real object, you can choose to use a virtual reference when you don’t want the real object to be accessed. The only thing it does is get notified when the object is GC and do some follow-up work.

The reference to Finalize method is FinalReference, which is one of the other two references mentioned above. If the reference is FinalReference, the reference can be used to clean up objects of Finalize method.

Realize the principle of

In the above references, except for strong references, the other several have corresponding implementation classes, which inherit Reference, and all the essence is also in this class.

Reference has several important parameters, some of which are closely related to GC: referent: The object being referenced and treated specially by GC. Queue: RererenceQueue is a Reference queue, which is used to store the Reference object. When creating a Reference, you can optionally pass in the second parameter. Next: Use the next variable to form a linked list structure when the Reference object is placed in RererenceQueue. Pending: This object is used by the JVM and is the Reference object currently being processed.

The main thread in Reference is the Reference Handler, which polls pending for data, and if pending is set to a value by the JVM, it will queue it. It’s the Cleaner object for out-of-heap memory applications, and it just performs its clean method, it doesn’t put it in a queue.

Once the Reference object has been queued, it can be pulled out for processing using a single thread.

Text is too dry, still need code:

final ReferenceQueue queue = new ReferenceQueue();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Reference reference = queue.remove();
System.out.println(reference + "Recycled");
} catch (InterruptedException e) {

}
}
}
}).start();

Object o = new Object();
Reference root = new WeakReference(o, queue);
System.out.println(root);
o = null;
System.gc();
System.in.read();
Copy the code

This code initializes a ReferenceQueue and then initializes a thread that loops to retrieve data from the queue, because when a soft, weak or vreferencequeue object is reclaimed by GC, the reference will be placed in the corresponding ReferenceQueue, which will be taken out for printing. It’s more about doing some cleaning up.

The result of executing the code above:

Java. Lang. Ref. WeakReference @ 34374 ed5 0.174: [Full GC (System) 0.175: [CMS: 0K-> 037k (12288K), 0.0146570 secs] 1231K-> 1237k (19712K), [CMS Perm: 2692K->2690K(21248K)], 0.0147430 secs] [Times: User sys = = 0.02 0.00, real = 0.01 secs] Java lang. Ref. The WeakReference @ 34374 ed5 recyclingCopy the code

In this way, interested students can verify other references.

conclusion

type The life cycle use
Soft references Until you run out of memory The cache
A weak reference The next time the GC Cache (WeakHashMap)
Phantom reference The next time the GC Off-heap memory management