devstory

Le Tutoriel de Java WeakReference

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

1. WeakReference

La classe java.lang.ref.WeakReference est utilisée pour créer un objet qui enveloppe (wrap) un autre objet - innerObject. L'objet qu'il enveloppe peut être supprimé de la mémoire par Garbage Collector (GC) s'il n'est plus utilisé ailleurs que par 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;
    }
}
Pour mieux comprendre, observer le code ci-dessous:
AnyObject innerObject = new AnyObject("Obj1");

WeakReference weakRef = new WeakReference(innerObject);
Dans le code ci-dessus, nous avons l'objet innerObject, qui est utilisé comme paramètre pour créer l'objet weakRef, ou en d'autres termes innerObject est utilisé par weakRef.
En règle générale, si un objet est utilisé quelque part, il est utile et ne peut pas être supprimé de la mémoire. Cependant, WeakReference est une classe spéciale, considérée comme plus faible que Garbage Collector (GC). L'objet enveloppé dans une WeakReference peut toujours être supprimé de la mémoire par GC s'il n'est plus utilisé ailleurs plus fort que 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
Dans l'exemple ci-dessus, on convoque la méthode System.gc() pour demander au Garbage Collector de travailler. Cette demande n'a pas d'effet immédiat. En règle générale, GC est une machine sophistiquée et complexe qui fonctionne automatiquement et vous ne pouvez l'interférer que de manière limitée.
Dans l'exemple suivant, on n'appellera pas la méthode System.gc(), mais GC supprimera toujours l'objet enveloppé dans WeakReference après un certain temps s'il n'est plus utilisé ailleurs plus fort que 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)
Toutes les méthodes de WeakReference sont héritées de la classe parentale.
// Methods inherited from parent.
public T get()  
public void clear()  
public boolean isEnqueued()  
public boolean enqueue()

2. Primitive Inner Object

Une valeur primitive n'est pas une référence bien qu'elle puisse être écrite comme une référence. Donc, s'il est enveloppé dans une WeakReference, il ne sera pas supprimé de la mémoire par GC.
Integer innerObj1 = 1000;
Double innerObj2 = 2000.2;
String innerObj3 = "SomeString";
Par exemple:
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

Si un objet est créé par un opérateur "new" et enveloppé dans une WeakReference, il sera supprimé de la mémoire par GC s'il n'est plus utilisé ailleurs plus fort que 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);
L'objet enveloppé dans une WeakReference agit comme un diner dans un restaurant. Lorsque les convives ont fini de manger, ils sont prêts à quitter la table même si à ce moment-là le restaurant a de nombreuses tables vides. SoftReference est un peu différent de WeakReference, les convives peuvent s'asseoir et ne partir que si le restaurant n'a plus de tables libres ou si le nombre de tables libres disponibles est inférieur à une valeur sûre.

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

Créer un objet WeakReference qui enveloppe l'objet innerObject. Si innerObject est supprimé de la mémoire par GC, cet objet WeakReference sera ajouté dans queue.
WeakReference(T innerObject, ReferenceQueue<? super T> queue)
Par exemple:
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

Ensuite, on a besoin d'un exemple plus complexe. Dans cet exemple, les objets Employee sont ajoutés à une Company. Et un objet List contenant une liste de références faibles à chaque objet Employee. Tant que la Company stocke les objets Employee, ils ne seront pas supprimés de la mémoire par le 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