1. Java引用介绍

Java从1.2版本开始引入了4种引用,这4种引用的级别由高到低依次为:

强引用  >  软引用  >  弱引用  >  虚引用

StrongReference、 SoftReference、 WeakReference、PhantomReference (传说中的幽灵引用)

⑴ 强引用(Strong Reference)

强引用是使用最普遍的引用,也是赋值的默认引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

 

⑵ 软引用(Soft Reference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它

如果内存空间不足了,就会回收这些对象的内存

只要垃圾回收器没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的高速缓存

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

 

⑶ 弱引用(Weak Reference)

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期

在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

 

⑷ 虚引用(Phantom Reference)

“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收器回收的活动

虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

 

四种引用回收情景

级别

什么时候被垃圾回收

用途

生存时间

强引用

从来不会

对象的一般状态

JVM停止运行时终止

软引用

在内存不足时

对象高速缓存

内存不足时终止

弱引用

在垃圾回收时

对象缓存

gc运行后终止

虚引用

Unknown

Unknown

Unknown

 

Java 4 种引用使用场景

StrongReference、 SoftReference、 WeakReference、PhantomReference (传说中的幽灵引用)

这 4 种类型的引用与 GC 有着密切的关系, 下面逐一来看它们的定义和使用场景 :

1. Strong Reference

StrongReference 是 Java 的默认引用实现,  它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收

@Test  
public void strongReference() {  
    Object referent = new Object();  
      
    /** 
     * 通过赋值创建 StrongReference  
     */  
    Object strongReference = referent;  
      
    assertSame(referent, strongReference);  
      
    referent = null;  
    System.gc();  
      
    /** 
     * StrongReference 在 GC 后不会被回收 
     */  
    assertNotNull(strongReference);  
}  

 

2. WeakReference & WeakHashMap

WeakReference,是一个弱引用,  当所引用的对象在 JVM 内不再有强引用时, GC 后 weak reference 将会被自动回收

@Test  
public void weakReference() {  
    Object referent = new Object();  
    WeakReference<Object> weakRerference = new WeakReference<Object>(referent);  
  
    assertSame(referent, weakRerference.get());  
      
    referent = null;  
    System.gc();  
      
    /** 
     * 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收 
     */  
    assertNull(weakRerference.get());  
}  

WeakHashMap 使用 WeakReference 作为 key

一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry

@Test  
public void weakHashMap() throws InterruptedException {  
    Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();  
    Object key = new Object();  
    Object value = new Object();  
    weakHashMap.put(key, value);  
  
    assertTrue(weakHashMap.containsValue(value));  
      
    key = null;  
    System.gc();  
      
    /** 
     * 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理 
     */  
    Thread.sleep(1000);  
      
    /** 
     * 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry 
     */  
    assertFalse(weakHashMap.containsValue(value));  
}  

 

3. SoftReference

SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 软引用SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用

@Test  
public void softReference() {  
    Object referent = new Object();  
    SoftReference<Object> softRerference = new SoftReference<Object>(referent);  
  
    assertNotNull(softRerference.get());  
      
    referent = null;  
    System.gc();  
      
    /** 
     *  soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用 
     */  
    assertNotNull(softRerference.get());  
}  

 

 

参考推荐

Java 引用总结

Java中内存优化的SoftReference 和 WeakReference浅析