Not long ago, I interviewed some candidates for a job as a Java Senior Development engineer. I often interview them and say, "Can you introduce me to some weak references in Java?" "If the interviewer says," Well, is it about garbage collection? ", I will be basically satisfied, I do not expect the answer is an article description of the paper."
However, I was surprised to find that in nearly 20 candidates with an average of 5 years of development experience and a high academic background, only two were aware of the existence of weak references, but only one of the two people really knew about it. In the interview process, I also tried to hint something, to see if someone suddenly said "it is this ah", the result is disappointing to me. I began to wonder why this piece of knowledge was so neglected that weak references were a useful feature, and this feature was introduced 7 years ago when Java 1.2 was released.
Well, I don't expect you to be an expert on weak references after reading this, but I think at least you should know what weak references are, how to use them, and what scenarios to use. Since they are some unknown concepts, let me briefly explain the first three questions.
Strong reference (Strong Reference)
Strong references are the references we use frequently, and they are written as follows:
Copy Code code as follows:
StringBuffer buffer = new StringBuffer ();
A StringBuffer object is created and the (strong) reference to the object is stored in the variable buffer. Yes, this is the pediatric operation (please forgive me for saying that). The most important thing about a strong reference is that it can make the reference strong (strong), which determines its interaction with the garbage collector. Specifically, if an object is reachable through a string of strong reference links (strongly reachable), it will not be recycled. If you don't want the objects you're using to be recycled, that's exactly what you need.
But the strong quotes are so strong
In a program, it is somewhat less common to set a class to be extensible, and of course it can be marked with a final implementation by a class. Or it can be more complicated by returning an interface (Interface) by a factory method that contains an unknown number of implementations internally. For example, we want to use a class called a widget, but this class cannot be inherited, so new functionality cannot be added.
But what do we do if we want to track additional information about the Widget object? Suppose we need to record the serial number of each object, but since the Widget class does not contain this attribute and cannot be extended we cannot add this attribute. In fact, there is no problem, HashMap can completely solve the above problems.
Copy Code code as follows:
Serialnumbermap.put (widget, widgetserialnumber);
The surface appears to be fine, but strong references to widget objects are likely to cause problems. We can be sure that when a widget serial number is not needed, we should remove the entry from the map. If we do not remove it, it may cause a memory leak, or we remove the widgets we are using when we manually remove it, which can result in the loss of valid data. In fact, these problems are very similar, this is not the garbage collection mechanism of language management memory often encountered problems. But we don't have to worry about that because we use the Java language that has the garbage collection mechanism.
Another potential problem with a strong reference is caching, especially for large files such as pictures. Let's say you have a program that handles user-supplied images, which is usually done by caching images, because loading pictures from disk is costly, and we also want to avoid two of the same image data in memory.
Caching is designed to prevent us from loading unwanted files again. You will soon find that in the cache there is always a reference to the image data that has been pointed to in memory. Using a strong reference forces the image data to remain in memory, which requires you to decide when the picture data is not needed and manually removed from the cache, allowing the garbage collector to reclaim it. So once again you are forced to do the work of the garbage collector and decide for yourself which object to clean up.
Weak reference (Weak Reference)
A weak reference simply means that the ability to leave an object in memory is not so strong a reference. Using WeakReference, the garbage collector will help you decide when the referenced object will be recycled and remove the object from memory. Create a weak reference as follows:
Copy Code code as follows:
eakreference<widget> weakwidget = new weakreference<widget> (Widget);
A real Widget object can be obtained using weakwidget.get (), because a weak reference cannot stop the garbage collector from reclaiming it, and you will find that it suddenly returns NULL when you use get when there is no strong reference to the Widget object.
The easiest way to solve the problem of recording the above widget sequence is to use the Java built-in Weakhashmap class. Weakhashmap and HashMap almost the same, the only difference is its key (not the value!!! ) Use the WeakReference reference. When the key of the Weakhashmap is marked as garbage, the corresponding entry for the key is automatically removed. This avoids the problem of manually removing the unwanted widget objects. Using Weakhashmap can be easily converted to HashMap or map.
Reference queues (Reference queue)
Once a weak reference object begins to return null, the object that the weak reference points to is marked as garbage. This weak reference object (not the object it points to) is useless. Some cleanup is usually required at this time. For example, Weakhashmap will remove useless entries at this time to avoid saving unlimited growth of meaningless weak references.
Reference queues make it easy to track unwanted references. When you pass in a Referencequeue object when you construct WeakReference, the reference object is automatically added to the reference queue when the object to which it points is marked as garbage. Next, you can process the incoming reference queues in a fixed cycle, such as doing some cleanup work to handle these useless reference objects.
Four types of references
There are actually four different kinds of references in Java, from strong to weak, they are strong references, soft references, weak references, and virtual references. The above section describes strong references and weak references, and the remaining two, soft and virtual references are described below.
Soft reference (Soft Reference)
Soft references are basically the same as weak references, but are more powerful than weak references to prevent garbage collections from reclaiming objects that they point to. If an object is reachable by a weak reference, the object is destroyed by the garbage collector's subsequent recycle cycle. However, if a soft reference can be reached, the object will stay longer in memory for more time. The garbage collector reclaims objects that are reachable by soft references when there is not enough memory.
Because soft references can reach objects that are longer than weakly referenced objects that can be trapped in memory, we can use this feature to do caching. In this way, you can save a lot of things, the garbage collector will be concerned about which type of arrival and the amount of memory consumed to deal with.
Virtual reference (Phantom Reference)
Unlike soft references, where the weak reference is different, the object pointed to by the virtual reference is very fragile, and we cannot get the object to which it is pointing by getting methods. Its only function is to be added to the reference queue when the object it points to is reclaimed, and the object being used as a record of the reference has been destroyed.
The weak reference is added to the reference queue when the pointed object of the weak reference becomes weak and the reference is reachable. This occurs before object destructor or garbage collection actually occurs. In theory, this object to be reclaimed can be revived in a destructor that does not conform to the specification. But this weak reference will be destroyed. A virtual reference is not added to the reference queue until the object to which it points is removed from memory. Its Get method always returns null in order to prevent the almost destroyed object from being revived.
The virtual reference usage scenario is mainly composed of two. It allows you to know exactly when the object it refers to is removed from memory. In fact, this is the only way in Java. This is particularly true in the case of large files that deal with similar pictures. When you are sure that a picture data object should be recycled, you can use a virtual reference to determine that the object is recycled and continue loading the next picture. This allows you to avoid terrible memory overflow errors as much as possible.
2nd, a virtual reference can avoid a lot of destructor problems. The Finalize method enables these objects to be resurrected by creating strong references that point to objects that are quickly destroyed. However, an object that rewrites the Finalize method needs to undergo two separate garbage collection cycles if it wants to be recycled. In the first cycle, an object is marked as recyclable, which in turn can be destructor. But because there is still a faint possibility that this object will revive in the process of deconstruction. In this case, the garbage collector needs to run again before the object is actually destroyed. Because the destructor may not be timely, it is necessary to undergo an indeterminate amount of garbage collection cycles before invoking the object's destructor. This means that there may be a lot of delay in actually cleaning up the object. This is why annoying memory overflow errors can occur when most of the heap is marked as garbage.
With a virtual reference, the above situation will be the blade, and when a virtual reference is added to the reference queue, you have absolutely no way to get a destroyed object. Because of this time, the object has been destroyed from memory. Because a virtual reference cannot be used to regenerate an object that it points to, its objects are cleaned up during the first cycle of garbage collection.
Obviously, the Finalize method does not recommend being overridden. Because virtual references are clearly safe and efficient, eliminating the Finalize method can make virtual machines significantly simpler. Of course you can also rewrite this method to achieve more. It all depends on personal choice.
Summarize
I want to see here, a lot of people start whining, why do you want to talk about an old-age API for the past decade, well, in my experience, many Java programmers don't know much about this knowledge, and I think it's necessary to have some deep understanding, and I hope you get something out of this article.