Java 2 platform introducedjava.lang.refPackages, including classes that allow you to reference objects without leaving them in memory. These classes also provide limited interaction with the garbage collector. Peter Haggar analyzedSoftReference,WeakReferenceAndPhantomReferenceClass Functions and behaviors, and provides some suggestions on the programming style for the use of these classes.
When we first introducedjava.lang.refPackage (includingSoftReference,WeakReferenceAndPhantomReferenceClass), its practicality is obviously exaggerated. The classes it contains may be useful, but some limitations of these classes make them not very attractive, and their applications will be particularly limited to solving a specific category of issues.
Garbage collection Overview
The main function of the reference class is to reference objects that can still be recycled by the garbage collector. Before introducing a reference class, we can only use strong reference ). For example, the following line of code shows a strong reference.obj:
Object obj = new Object(); |
objThis reference references an object stored in the heap. As longobjIf a reference still exists, the garbage collector will never release the storage space used to hold the object.
WhenobjOut of range or explicitly specifiednullThe garbage collector considers that there is no other reference to this object, and it can be collected. However, you also need to pay attention to the important details: the collection of objects alone does not mean that the garbage collector can recycle it at a specified operation. Due to different garbage collection algorithms, some algorithms analyze objects with shorter lifetime more frequently than older objects with longer lifetime. Therefore, an object that can be collected may never be recycled. This situation may occur if the program ends before the Garbage Collector releases the object. Therefore, in summary, you will never guarantee that the objects available for collection will always be collected by the garbage collector.
This information is very important for you to analyze reference classes. Because garbage collection has a specific nature, the reference classes may not be as useful as you originally thought. However, they are useful for specific problems. Soft reference, weak reference, and phantom reference objects provide three different methods to reference heap objects without interfering with collection. Each referenced object has different behaviors, and their interaction with the garbage collector is also different. In addition, these new reference classes all show more weak references than typical references. In addition, an object in the memory can be referenced by multiple references (strong reference, soft reference, weak reference, or virtual reference. Before further discussion, let's take a look at some terms:
- Stronugly reachable ):Objects that can be accessed through strong references.
- Softly reachable ):Objects that are not highly accessible and can be accessed through soft references.
- Weakly reachable ):Objects that are neither strong or soft or accessible through weak references.
- Phantomly reachable ):It is not a strong object, soft object, or weak object. It has ended and can be accessed through virtual reference.
- Clear:Set the referent field of the referenced object
nullAnd declare the object referenced by the reference class in the heapEndable.
Softreference class
SoftReferenceA typical use of class is for memory-sensitive high-speed cache.SoftReferenceThe principle is to ensure that all soft references are cleared before the JVM reports memory insufficiency when the object is referenced. The key is that the Garbage Collector may (or may not) release software and objects at runtime. Whether the object is released depends on the garbage collector algorithm and the amount of memory available when the garbage collector is running.
Weakreference class
WeakReferenceA typical use of a class is canonicalized mapping ). In addition, for objects with relatively long lifetime and Low Re-creation overhead, weak references are also useful. The key is that if the spam collector encounters a weak object during runtime, it will be releasedWeakReferenceThe referenced object. However, note that the spam Collector may have to run multiple times to locate and release weak accessible objects.
Phantomreference class
PhantomReferenceClass can only be used to track the upcoming collection of referenced objects. It can also be used for pre-mortem cleanup.PhantomReferenceMust beReferenceQueueClass. YesReferenceQueueIt can act as a notification mechanism. When the Garbage Collector determines that an object is virtual and accessible,PhantomReferenceThe object is placed in it.ReferenceQueue. SetPhantomReferencePut the object inReferenceQueueIt is also a notification, indicatingPhantomReferenceThe object referenced by the object has ended and can be collected. This allows you to take action just before the memory occupied by the object is recycled.
Interaction between the Garbage Collector and reference
The garbage collector can freely release the memory occupied by objects that are no longer highly accessible. If the spam collector discovers software and objects, the following situations occur:
SoftReferenceThe referent field of the object is setnullSo that the object does not referenceheapObject.
SoftReferenceReferencedheapObject declaredfinalizable.
- When
heapObjectfinalize()Method is run and the memory occupied by this object is released,SoftReferenceThe object is added to itsReferenceQueue(If the latter exists ).
If the spam collector finds weak and accessible objects, the following situations occur:
WeakReferenceThe referent field of the object is setnullSo that the object does not referenceheapObject.
WeakReferenceReferencedheapObject declaredfinalizable.
- When
heapObjectfinalize()When the method is run and the memory occupied by the object is released,WeakReferenceThe object is added to itsReferenceQueue(If the latter exists ).
If the spam collector discovers virtual possibilities and objects, the following situations occur:
PhantomReferenceReferencedheapObject declaredfinalizable.
- Unlike soft references and weak references,
PhantomReferenceAdded to the heap object before it is released.ReferenceQueue. (Remember, allPhantomReferenceAll objects must be associatedReferenceQueue.) This allows you to take action before the heap object is recycled.
Consider the code in Listing 1. Figure 1 shows the code execution.
Listing 1. sample code using WeakReference and ReferenceQueue
//Create a strong reference to an objectMyObject obj = new MyObject(); //1//Create a reference queueReferenceQueue rq = new ReferenceQueue(); //2 //Create a weakReference to obj and associate our reference queueWeakReference wr = new WeakReference(obj, rq); //3 |
Figure 1. Object layout after the code of the row/1, // 2 and // 3 in Listing 1 is executed
Figure 1 shows the status of each object after each line of code is executed. Create row // 1MyObjectObject, while row // 2 is createdReferenceQueueObject. Row // 3 create a reference objectMyObjectOfWeakReferenceObject.ReferenceQueue. Note that each object reference (obj,rqAndwr. To use these reference classes, you must cancelMyObjectStrong reference of the object, the method isobjSetnull. As mentioned above, if you do not do this, the objectMyObjectIt will never be recycled, and any advantages of the referenced class will be weakened.
Each referenced class hasget()Method, whileReferenceQueueClass haspoll()Method.get()Method to return a reference to the referenced object. InPhantomReferenceOnget()Always Returnsnull. This is becausePhantomReferenceOnly used for tracking and collection.poll()Method returns the referenced object that has been added to the queue. If no object exists in the queue, it returnsnull. Therefore, after listing 1 is executed, callget()Andpoll()The result may be:
wr.get(); //returns reference to MyObjectrq.poll(); //returns null |
Now let's assume that the garbage collector is running. BecauseMyObjectThe object is not released, soget()Andpoll()Method returns the same value;objThe object is still strongly referenced. In fact, the object layout remains unchanged, as shown in figure 1. However, consider the following code:
obj = null;System.gc(); //run the collector |
After this code is executed, the object layout is shown in 2:
Now, callget()Andpoll()Different results will be generated:
wr.get(); //returns nullrq.poll(); //returns a reference to the WeakReference object |
This situation indicates that,MyObjectObject.WeakReferenceObject) is no longer available. This means that the garbage collector is released.MyObjectMemory occupied, so thatWeakReferenceThe object can be placed in itReferenceQueue. In this way, you can know whenWeakReferenceOrSoftReferenceClassget()Method returnnullAn object is declaredfinalizableAnd may (but not necessarily) be collected. Only whenheapAfter the object ends completely and its memory is recycled,WeakReferenceOrSoftReferenceWill be placed in the associatedReferenceQueue. Listing 2 shows a complete runnable program that shows part of these principles. The code itself is quite descriptive. It contains many comments and print statements to help you understand.
List 2. shows the complete program for referencing the class Principle
import java.lang.ref.*;class MyObject{ protected void finalize() throws Throwable { System.out.println("In finalize method for this object: " + this); }}class ReferenceUsage{ public static void main(String args[]) { hold(); release(); } public static void hold() { System.out.println("Example of incorrectly holding a strong " + "reference"); //Create an object MyObject obj = new MyObject(); System.out.println("object is " + obj); //Create a reference queue ReferenceQueue rq = new ReferenceQueue(); //Create a weakReference to obj and associate our reference queue WeakReference wr = new WeakReference(obj, rq); System.out.println("The weak reference is " + wr); //Check to see if it's on the ref queue yet System.out.println("Polling the reference queue returns " + rq.poll()); System.out.println("Getting the referent from the " + "weak reference returns " + wr.get()); System.out.println("Calling GC"); System.gc(); System.out.println("Polling the reference queue returns " + rq.poll()); System.out.println("Getting the referent from the " + "weak reference returns " + wr.get()); } public static void release() { System.out.println(""); System.out.println("Example of correctly releasing a strong " + "reference"); //Create an object MyObject obj = new MyObject(); System.out.println("object is " + obj); //Create a reference queue ReferenceQueue rq = new ReferenceQueue(); //Create a weakReference to obj and associate our reference queue WeakReference wr = new WeakReference(obj, rq); System.out.println("The weak reference is " + wr); //Check to see if it's on the ref queue yet System.out.println("Polling the reference queue returns " + rq.poll()); System.out.println("Getting the referent from the " + "weak reference returns " + wr.get()); System.out.println("Set the obj reference to null and call GC"); obj = null; System.gc(); System.out.println("Polling the reference queue returns " + rq.poll()); System.out.println("Getting the referent from the " + "weak reference returns " + wr.get()); }} |
Purpose and Style
The principle behind these classes is to avoid leaving objects in the memory during application execution. Instead, you reference an object using soft reference, weak reference, or virtual reference, so that the garbage collector can release the object at will. This is useful when you want to minimize the heap memory used by your application in its lifecycle. You must remember that to use these classes, you cannot retain strong references to objects. If you do this, it will waste any of the benefits provided by these classes.
In addition, you must use the correct programming style to check whether the collector has recycled the object before using it. If yes, you must recreate the object first. This process can be completed in different programming styles. Selecting an incorrect style will cause problems. ConsiderWeakReferenceCode style for retrieving referenced objects:
Listing 3. retrieving the style of the referenced object
obj = wr.get();if (obj == null){ wr = new WeakReference(recreateIt()); //1 obj = wr.get(); //2}//code that works with obj |
After studying this code, seeWeakReferenceAnother Code style for retrieving referenced objects:
Listing 4. Retrieving another style of referenced objects
obj = wr.get();if (obj == null){ obj = recreateIt(); //1 wr = new WeakReference(obj); //2}//code that works with obj |
Compare the two styles to see if you can determine which one is feasible or not. The style shown in listing 3 is not always feasible in all cases, but the style shown in Listing 4 is fine. The reason for the bad style in listing 3 is,ifAfter the entity of the block endsobjIt is not necessarily a non-null value. Consider what if the Garbage Collector runs after the row // 1 in listing 3 but before the row // 2 is executed.recreateIt()Method will re-create the object, but it will beWeakReferenceReferences, rather than strong references. Therefore, if the collector runs before a strong reference is applied to a re-created object in row/2, the object will be lost,wr.get()Returnsnull.
Listing 4 does not solve this problem because the row/1 re-creates an object and specifies a strong reference for it. Therefore, if the Garbage Collector runs after the row (but before the row // 2), the object will not be recycled. Then, row // 2 will create a pairobjOfWeakReference. When using thisifAfter the blockobjThen, you shouldobjSetnullSo that the garbage collector can recycle this object to make full use of weak references. Listing 5 shows a complete program that shows the differences between the styles we described just now. (To run the program, there must be a "Temp. fil" file in the running directory.
Listing 5. shows the complete program of the correct and incorrect programming style
import java.io.*;import java.lang.ref.*;class ReferenceIdiom{ public static void main(String args[]) throws FileNotFoundException { broken(); correct(); } public static FileReader recreateIt() throws FileNotFoundException { return new FileReader("temp.fil"); } public static void broken() throws FileNotFoundException { System.out.println("Executing method broken"); FileReader obj = recreateIt(); WeakReference wr = new WeakReference(obj); System.out.println("wr refers to object " + wr.get()); System.out.println("Now, clear the reference and run GC"); //Clear the strong reference, then run GC to collect obj. obj = null; System.gc(); System.out.println("wr refers to object " + wr.get()); //Now see if obj was collected and recreate it if it was. obj = (FileReader)wr.get(); if (obj == null) { System.out.println("Now, recreate the object and wrap it in a WeakReference"); wr = new WeakReference(recreateIt()); System.gc(); //FileReader object is NOT pinned...there is no //strong reference to it. Therefore, the next //line can return null. obj = (FileReader)wr.get(); } System.out.println("wr refers to object " + wr.get()); } public static void correct() throws FileNotFoundException { System.out.println(""); System.out.println("Executing method correct"); FileReader obj = recreateIt(); WeakReference wr = new WeakReference(obj); System.out.println("wr refers to object " + wr.get()); System.out.println("Now, clear the reference and run GC"); //Clear the strong reference, then run GC to collect obj obj = null; System.gc(); System.out.println("wr refers to object " + wr.get()); //Now see if obj was collected and recreate it if it was. obj = (FileReader)wr.get(); if (obj == null) { System.out.println("Now, recreate the object and wrap it in a WeakReference"); obj = recreateIt(); System.gc(); //FileReader is pinned, this will not affect //anything. wr = new WeakReference(obj); } System.out.println("wr refers to object " + wr.get()); }} |
Summary
If used properly, the reference class is still very useful. However, since the behavior of the garbage collector on which they depend is sometimes unpredictable, their practicality will be affected. Whether they can be effectively used depends on whether the correct programming style is applied. The key is to understand how these classes are implemented and how they are programmed.