Java weak reference

  一个对象被回收,必须满足两个条件: 没有任何引用指向它和GC在运行。把所有指向某个对象的引用置空来保证这个对象在下次GC运行时被回收。

1 Object c = new Car(); 
2 c = null;

  手动置空对象是繁琐且违背自动回收理念的。对于简单对象,当使用它的方法执行完毕后,指向它的引用会出栈,所以在下一次GC执行时会回收它。但是缓存中的引用的生命周期与主程序一致。回收缓存中的对象需要程序员去做,这违背了GC的本质(自动回收可以回收的对象)。

  相对于前面的强引用(strong reference),Java中引入了弱引用(weak reference)。如果一个对象仅被弱引用指向,那么GC运行时会回收这个对象。弱引用语法:

1 WeakReference<Car> weakCar = new WeakReference(Car)(car);

  当要获取弱引用指向的对象时,需要判断它是否已经被回收:

1 weakCar.get();

  如果此方法返回值为空,则说明weakCar指向的对象已经被回收了。

  实例:

 1 package weakreference;
 2 /**
 3  * @author wison
 4  */
 5 public class Car {
 6     private double price;
 7     private String colour;
 8     
 9     public Car(double price, String colour){
10         this.price = price;
11         this.colour = colour;
12     }
13     
14     public double getPrice() {
15         return price;
16     }
17     public void setPrice(double price) {
18         this.price = price;
19     }
20     public String getColour() {
21         return colour;
22     }
23     public void setColour(String colour) {
24         this.colour = colour;
25     }
26     
27     public String toString(){
28         return colour +"car costs $"+price;
29     }
30     
31 }
 1 package weakreference;
 2 
 3 import java.lang.ref.WeakReference;
 4 
 5 /**
 6  * @author wison
 7  */
 8 public class TestWeakReference {
 9 
10     
11     public static void main(String[] args) {
12         
13         Car car = new Car(22000,"silver");
14         WeakReference<Car> weakCar = new WeakReference<Car>(car);
15         
16         int i=0;
17         
18         while(true){
19             if(weakCar.get()!=null){
20                 i++;
21                 System.out.println("Object is alive for "+i+" loops - "+weakCar);
22             }else{
23                 System.out.println("Object has been collected.");
24                 break;
25             }
26         }
27     }
28 
29 }

  程序运行一段时间后打印出“Object has been collected.",说明弱引用指向的对象被回收了。Java编译器进入while循环后发现强引用car已经没有被使用了,所以进行了优化。

  修改TestWeakReference.java:

 1 package weakreference;
 2 
 3 import java.lang.ref.WeakReference;
 4 
 5 /**
 6  * @author wison
 7  */
 8 public class TestWeakReference {
 9 
10     
11     public static void main(String[] args) {
12         
13         Car car = new Car(22000,"silver");
14         WeakReference<Car> weakCar = new WeakReference<Car>(car);
15         
16         int i=0;
17         
18         while(true){
19             System.out.println("here is the strong reference 'car' "+car);
20             if(weakCar.get()!=null){
21                 i++;
22                 System.out.println("Object is alive for "+i+" loops - "+weakCar);
23             }else{
24                 System.out.println("Object has been collected.");
25                 break;
26             }
27         }
28     }
29 
30 }

  弱引用指向的对象不会被回收,因为while循环体里面使用了强引用指向的对象。GC运行的不确定性决定了弱引用指向的对象回收时机的不确定性。所以用弱引用指向的对象是有价值被缓存的,且是很消耗内存的对象。

  

  ReferenceQueue

  在弱引用指向的对象被回收后,Java提供了一个ReferenceQueue来保存指向的对象已经被回收的引用,用法是在定义WeakReference时将一个ReferenceQueue的对象作为参数传入构造函数。

  其他类型的引用

  soft reference

  soft reference和weak reference一样,但被GC回收时多1个条件:当系统内存不足时,soft reference指向的对象才会被回收。因此,soft reference比weak reference更适合成为缓存对象的引用,尽可能地维持缓存对象,减少创建它们所需的空间和时间。

  phantom reference、WeakHashMap和WeakCache

  to be continued

  参考资料

  不只是给面试加分 -- Java WeakReference的理解与使用

原文地址:https://www.cnblogs.com/WJQ2017/p/7687090.html