o7planning

Java WeakReference Tutorial with Examples

  1. WeakReference
  2. Primitive Inner Object
  3. Non-Primitive Inner Object
  4. WeakReference(T, ReferenceQueue<? super T>)
  5. Complex example

1. WeakReference

java.lang.ref.WeakReference class is used to create an object that wraps another object - innerObject. The object it wraps can be removed from memory by Garbage Collector (GC) if it is no longer being used somewhere else stronger than GC.
AnyObject.java
package org.o7planning.beans;

public class AnyObject {
    private String val;
    public AnyObject(String val) {
        this.val = val;
    }
    public String getVal() {
        return this.val;
    }
}
For easy understanding, see the code below:
AnyObject innerObject = new AnyObject("Obj1");

WeakReference weakRef = new WeakReference(innerObject);
In the above code we have innerObject object, which is used as a parameter to create weakRef object, or in other words innerObject is being used by weakRef.
In common sense, if an object is in use somewhere, it is useful and cannot be removed from memory. However, WeakReference is a special class, which is considered weaker than Garbage Collector (GC). Object wrapped in a WeakReference can still be removed from memory by GC if it is no longer being used somewhere else stronger than GC.
WeakReference_obj_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.WeakReference;

import org.o7planning.beans.AnyObject;

public class WeakReference_obj_ex1 {

    public static void main(String[] args) throws InterruptedException {
        // Create innerObject reference points to AnyObject("Obj1").
        AnyObject innerObject = new AnyObject("Obj1");
        // Create WeakReference object using innerObject reference.
        WeakReference<AnyObject> weakRef = new WeakReference<AnyObject>(innerObject);
        
        System.out.println("weakRef.get(): " + weakRef.get());
        
        // Set innerObject reference to null (Points to null).
        innerObject = null;

        System.out.println("\nCall System.gc().\n");
        System.gc();
        Thread.sleep(3000);
        
        System.out.println("weakRef.get(): " + weakRef.get());
    }
}
Output:
weakRef.get(): org.o7planning.beans.AnyObject@5e91993f

Call System.gc().

weakRef.get(): null
In the above example we call System.gc() method to tell Garbage Collector to work. This request has no immediate effect. Basically, GC is a sophisticated and complex machine that works automatically and you can only interfere with it in a limited way.
In the next example, we won't actively call System.gc() method, but GC will still remove the object wrapped inside WeakReference after a while if it's no longer being used somewhere else stronger than GC.
WeakReference_obj_ex2.java
package org.o7planning.weakreference.ex;

import java.lang.ref.WeakReference;

import org.o7planning.beans.AnyObject;

public class WeakReference_obj_ex2 {

    public static void main(String[] args) throws InterruptedException {
         // Create innerObject reference points to AnyObject("Obj1").
        AnyObject innerObject = new AnyObject("Obj1");
        // Create WeakReference object using innerObject reference.
        WeakReference<AnyObject> weakRef = new WeakReference<AnyObject>(innerObject);
        
        System.out.println("weakRef.get(): " + weakRef.get());

        int i = 0;
        while(true)  {
            AnyObject innerObj = weakRef.get();
            if(innerObj == null)  {
                System.out.println("Inner object is removed by Garbage Collector");
                System.out.println("weakRef.get(): " + innerObj);
                break;
            }
            i++;
            System.out.println(i+ " weakRef.get(): " + innerObj);
        }
    }
}
Output:
weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
1 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
2 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f

.....

283516 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
283517 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
283518 weakRef.get(): org.o7planning.beans.AnyObject@5e91993f
Inner object is removed by Garbage Collector
weakRef.get(): null
WeakReference constructors
WeakReference(T referent)

WeakReference(T referent, ReferenceQueue<? super T> q)
All methods of WeakReference are inherited from parent class.
// Methods inherited from parent.
public T get()  
public void clear()  
public boolean isEnqueued()  
public boolean enqueue()

2. Primitive Inner Object

A primitive value is not a reference although it can be written like a reference. So if it is wrapped inside a WeakReference it will not be removed from memory by GC.
Integer innerObj1 = 1000;
Double innerObj2 = 2000.2;
String innerObj3 = "SomeString";
Example:
WeakReference_primitive_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.WeakReference;

public class WeakReference_primitive_ex1 {

    public static void main(String[] args) throws InterruptedException {
        Integer innerObj1 = 100;
        String  innerObj2 = "SomeString";
        
        WeakReference<Integer> weakRef1 = new WeakReference<Integer>(innerObj1);
        WeakReference<String> weakRef2 = new WeakReference<String>(innerObj2);
        
        System.out.println("weakRef1.get(): "  + weakRef1.get());
        System.out.println("weakRef2.get(): "  + weakRef2.get());
        
        // Points to null.
        innerObj1 = null;
        innerObj2 = null;
        
        System.out.println("\n--- Call System.gc(): ---\n");
        // Call GC:
         System.gc();
        Thread.sleep(3000);
        
        
        System.out.println("weakRef1.get(): "  + weakRef1.get());
        System.out.println("weakRef2.get(): "  + weakRef2.get());
    }
}
Output:
weakRef1.get(): 100
weakRef2.get(): SomeString

--- Call System.gc(): ---

weakRef1.get(): 100
weakRef2.get(): SomeString

3. Non-Primitive Inner Object

If an object is created by the "new" operator and wrapped inside a WeakReference, it will be removed from memory by GC if it is no longer being used somewhere else stronger than GC.
AnyObject innerObj1 = new AnyObject("Obj1");
String innerObj2 = new String("Obj2");
Integer innerObj3 = new Integer(1000);
String innerObj4 = new String("Obj4");

WeakReference<AnyObject> weakRef = new WeakReference<AnyObject>(innerObj1);
The object wrapped inside a WeakReference acts as a diner in a restaurant. When diners finish eating, they are ready to leave the table even if at that time the restaurant has many empty tables. SoftReference is a bit different from WeakReference, diners can sit back and only leave if the restaurant has no more free tables or the number of available free tables is less than a safe value.

4. WeakReference(T, ReferenceQueue<? super T>)

Create a WeakReference object that wraps innerObject object. If innerObject is removed from memory by GC, this WeakReference object will be added to the queue.
WeakReference(T innerObject, ReferenceQueue<? super T> queue)
Example:
WeakReference_c2_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

import org.o7planning.beans.AnyObject;

public class WeakReference_c2_ex1 {

    public static void main(String[] args) throws InterruptedException {

        AnyObject myAnyObject1 = new AnyObject("Obj1");
        AnyObject myAnyObject2 = new AnyObject("Obj2");

        ReferenceQueue<AnyObject> queue = new ReferenceQueue<AnyObject>();
        //
        WeakReference<AnyObject> weakRef1 = new WeakReference<AnyObject>(myAnyObject1, queue);
        WeakReference<AnyObject> weakRef2 = new WeakReference<AnyObject>(myAnyObject2, queue);

        System.out.println("weakRef1: " + weakRef1);
        System.out.println("weakRef2: " + weakRef2);
        System.out.println("weakRef1.get(): " + weakRef1.get());
        System.out.println("weakRef2.get(): " + weakRef2.get());

        // Set myAnyObject1 reference to null (Points to null).
        myAnyObject1 = null;

        System.out.println("\nCall System.gc().\n");
        System.gc();
        Thread.sleep(3000);

        // myAnyObject2 is still used.
        System.out.println("myAnyObject2: " + myAnyObject2);

        System.out.println("weakRef1.get(): " + weakRef1.get());
        System.out.println("weakRef2.get(): " + weakRef2.get());

        Reference<? extends AnyObject> removed = null;
        while ((removed = queue.poll()) != null) {
            System.out.println("removed: " + removed);
        }
    }
}
Output:
weakRef1: java.lang.ref.WeakReference@5e91993f
weakRef2: java.lang.ref.WeakReference@156643d4
weakRef1.get(): org.o7planning.beans.AnyObject@123a439b
weakRef2.get(): org.o7planning.beans.AnyObject@7de26db8

Call System.gc().

myAnyObject2: org.o7planning.beans.AnyObject@7de26db8
weakRef1.get(): null
weakRef2.get(): org.o7planning.beans.AnyObject@7de26db8
removed: java.lang.ref.WeakReference@5e91993f

5. Complex example

Next, we need a more complex example. In this example, Employee objects are added to a Company. And a List object containing a list of weak references to each Employee object. As long as Company stores Employee objects, they will not be removed from memory by GC.
WeakReference_ex1.java
package org.o7planning.weakreference.ex;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class WeakReference_ex1 {

    public static void main(String[] args) throws InterruptedException {
        Employee tom = new Employee("Tom");
        Employee jerry = new Employee("Jerry");
        Employee donald = new Employee("Donald");

        Employee[] employees = new Employee[] { tom, jerry, donald };

        Company company = new Company();

        ReferenceQueue<Employee> queue = new ReferenceQueue<>();
        List<WeakReference<Employee>> empListWeak = new ArrayList<WeakReference<Employee>>();

        for (int i = 0; i < employees.length; i++) {
            company.addEmployee(employees[i]);

            empListWeak.add(new WeakReference<Employee>(employees[i], queue));
        }
        // Free up the array.
        employees = null;

        System.out.println("Queue's polling returns null? " + (queue.poll() == null));

        for (WeakReference<Employee> wref : empListWeak) {
            System.out.println("wref.get().getFullName(): " + wref.get().getFullName());
        }

        //
        System.out.println("\n--- Remove some employees from company: ---\n");
        company.removeEmployee(tom);
        company.removeEmployee(jerry);
        tom = null;
        jerry = null;
        donald = null; // 'donald' is still used in company.

        System.gc();
        Thread.sleep(3000);

        Reference<? extends Employee> wref = null;
        System.out.println("Poll weak emp references garbage collected");
        while ((wref = queue.poll()) != null) {
            System.out.println("WeakReference of Emp removed from queue: " + wref);

        }
        System.out.println("done");
    }
}

class Employee {
   private String fullName;
   public Employee(String fullName)  {
       this.fullName = fullName;
   }
   public String getFullName()  {
       return this.fullName;
   }
}


class Company {
    private Set<Employee> employees = new HashSet<Employee>();

    public void addEmployee(Employee employee) {
        this.employees.add(employee);
    }

    public void removeEmployee(Employee employee) {
        employees.remove(employee);
    }
}
Output:
Queue's polling returns null? true
wref.get().getFullName(): Tom
wref.get().getFullName(): Jerry
wref.get().getFullName(): Donald

--- Remove some employees from company: ---

Poll weak emp references garbage collected
WeakReference of Emp removed from queue: java.lang.ref.WeakReference@1175e2db
WeakReference of Emp removed from queue: java.lang.ref.WeakReference@36aa7bc2
done

Java Basic

Show More