Reference Types in Java
Garbage collection is a sophisticated Java feature that takes care of automatic deallocation of objects that are not in use. The garbage collection mechanism reclaims memory from an object when there are no active references to that object. The types of references to an object also play an important role in garbage collection. This is because the decision to reclaim memory from the object heap is not just based on the active references. It is also based on the type of references.
What are Reference Types?
The types of references to an object determine when the object is selected for garbage collection. There are four types of references in Java, namely:
To ensure that your programs use memory efficiently, it is important to understand the different type of references and identify the most suitable reference types for your program.
A strong reference is a reference type that has the highest level of importance. An object that has an active strong reference to it is not selected for garbage collection except when cylindrical references are used.
Example: Student stu1 = new Student();
This statement creates a strong reference to the newly created Student object. When the garbage collector runs, the object is selected for deallocation only if its strong reference is set to null and there are no other references to it.
Example: stu1 = null;
This statement sets the strong reference stu1 to null. The object referred to by stu1 can now be garbage collected if there are no other references to it. Strong references are the most commonly used reference types in Java programs.
A soft reference is a reference type used to create a reference to an object that already has a strong reference to it. The object that the soft reference refers to is called the referent. An object that has no references other than soft references is reclaimed only if the memory is insufficient. You can create soft references by using the SoftReference class.
If you want to create a soft reference to an object, the first step is to create a strong reference to that object. The second step is to create a soft reference by passing the strong reference as a parameter to the SoftReference constructor.
Student stu1 = new Student();
SoftReference<Student> softStu = new SoftReference<Student>(stu1);
In the first statement, a referent object is created and allocated memory on the Student object heap. A strong reference, stu1, is also created for the new object. In the second statement, a soft reference, softStu, is created and allocated memory. Through the parameter passed in the constructor, softStu obtains an internal reference to the referent object. The soft reference, softStu, also acts as a strong reference to the SoftReference object on the heap.
How Soft References Work?
Suppose the strong reference, stu1, in the previous example is set to null and there is only a soft reference, softStu, to the referent Student object. If the garbage collector runs at this point, it can decide to reclaim memory from the Student object. However, this happens only if the JVM is about to encounter an OutOfMemory error.
If you want to prevent an object from getting reclaimed, you can resurrect the object by obtaining a strong reference to it. As long as the object is present in memory, you can use the get() method on the soft reference to obtain a strong reference to the referent object.
Example: Student resurrectedStu1 = softStu.get();
Soft references are used to create dynamic object pools. Suppose you are not aware of the size of an object pool and wish to allow it to grow dynamically while ensuring that the JVM efficiently reclaims memory from unused objects, you can go for soft references.
A weak reference is a reference type that is used when an object without any other references needs to be removed from memory. If the garbage collector finds an object with only weak references, it marks that object for deallocation from memory.
DBConnection stu = new Student();
WeakReference<DBConnection> weakStu = new WeakReference<DBConnection>(stu);
The above example creates a DBConnection object and a weak reference, weakStu, to the DBConnection object. When the garbage collector finds that weakStu is the only reference to the DBConnection object, it selects the DBConnection object for garbage collection.
How Weak References Work?
Weak references are most commonly used with a WeakHashMap. A WeakHashMap stores weak references as its keys so that the garbage collector can reclaim memory used by keys that are not in use.
For example, you want to store user metadata for each database connection. You can use a WeakHashMap to store weak references of the database connection as keys and user metadata as values. When a database connection object has only weak references, the garbage collector reclaims memory from its keys and removes its entry from the WeakHashMap.
What are Reference Queues?
A reference queue is a queue that the JVM maintains to store references selected for garbage collection. Suppose the garbage collector marks an object with only weak references for garbage collection. If there is a reference queue associated with the weak reference, then the garbage collector adds the weak reference to that queue. This happens in situations where even though an object is marked for garbage collection, the JVM retains it in queue so that the finalize method can be executed on it.
Student stu1 = new Student();
Student stu2 = new Student();
ReferenceQueue softStuQ = new ReferenceQueue();
ReferenceQueue weakStuQ = new ReferenceQueue();
SoftReference softR = new SoftReference (stu1, softStuQ);
WeakReference weakR = new WeakReference (stu2, weakStuQ);
This code uses two argument constructors of the SoftReference and WeakReference classes to associate a soft reference and a weak reference to their respective reference queues.
A phantom reference is a reference type that is associated with a reference queue at the time of creation. Like soft and weak references, if a referent object has no other references other than phantom references, then the object is eligible for garbage collection. However, phantom references are different because even if the referent object is selected for garbage collection, the phantom references are added to the reference queue only after the execution of the finalize method. Because of this reason, phantom references cannot be resurrected and calling the get() method returns null.