不仅仅有强引用
结构 
非强引用都继承java.lang.ref.Reference<T>抽象类
Reference.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public  abstract  class  Reference <T >     private  T referent;     volatile  ReferenceQueue<? super  T> queue;          Reference next;          Reference(T referent) {         this (referent, null );     }          Reference(T referent, ReferenceQueue<? super  T> queue) {         this .referent = referent;         this .queue = (queue == null ) ? ReferenceQueue.NULL : queue;     }     public  T get ()           return  this .referent;     }          public  void  clear ()           this .referent = null ;     }          public  boolean  enqueue ()           return  this .queue.enqueue(this );     }          public  boolean  isEnqueued ()           return  (this .queue == ReferenceQueue.ENQUEUED);     }      } 
引用分类 
强引用(Strong Reference) 
最常见的引用方式。强引用代表对象在被使用,不会被回收
软引用(Soft Reference) 
java.lang.ref.SoftReference 
一定程度上阻止回收,只要内存还足够,就不会被回收 
 
额外维护时间机制,综合考虑时间和空间因素决定是否回收
时间 clock - timestamp 计算多久没访问 
空间 freespace * SoftRefLRUPolicyMSPerMB 计算剩余空间容忍软引用生存时间,直观上看空间越多,对空闲软引用越宽容 
 
SoftReference.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  class  SoftReference <T > extends  Reference <T >          static  private  long  clock;          private  long  timestamp;     public  SoftReference (T referent)           super (referent);         this .timestamp = clock;     }     public  SoftReference (T referent, ReferenceQueue<? super  T> q)           super (referent, q);         this .timestamp = clock;     }          public  T get ()           T o = super .get();         if  (o != null  && this .timestamp != clock)             this .timestamp = clock;         return  o;     } } 
反射方法调用多次后,JVM会动态生成临时类优化性能,动态类就是使用软引用
弱引用(Weak Reference) 
java.lang.ref.WeakReference 
不会阻止回收,但是gc线程优先级比较低不一定很快回收掉,提供访问即如果还没回收掉就再次启用 
弱引用不会劫持对象,强引用断开,可能get出null 
 
无特殊逻辑,队列用不用都行
WeakReference.java 1 2 3 4 5 6 7 8 9 public  class  WeakReference <T > extends  Reference <T >     public  WeakReference (T referent)           super (referent);     }     public  WeakReference (T referent, ReferenceQueue<? super  T> q)           super (referent, q);     } } 
虚引用(Phantom Reference) 
java.lang.ref.PhantomReference 
形同虚设,不会影响回收,必须配合引用队列,用于跟踪对象GC活动 
原引用对象不可访问,get方法返回null,即不能重建强引用 
 
PhantomReference.java 1 2 3 4 5 6 7 8 9 10 11 public  class  PhantomReference <T > extends  Reference <T >          public  T get ()           return  null ;     }          public  PhantomReference (T referent, ReferenceQueue<? super  T> q)           super (referent, q);     } } 
非强引用的作用 
强引用下对象不会被回收,如果需要释放对象
没出作用域,还持有对象强引用,解决这种情况方法是手动置为null提前释放 
出了作用域,对象还被外围集合强引用持有,解决这种情况方法是手动从集合类移除 
 
非强引用提供了一种柔和的处理方式,如果一个对象上只有非强引用,虽然也是引用但有可能被回收,实现一种自动释放的效果
WeakHashMap 
WeakHashMap实现了自动清理,是弱引用的典型应用
如果忘了手动删除,那么可能内存泄漏 
如果删除早了,可能正在被使用中,那么数据丢失 
 
自动清理原理是key利用弱引用自动清理,Entry放入引用队列,用户操作触发Entry清理
底层的Entry实现了WeakReference,虽然Entry同时有key和value,但从构造函数可知只有key使用了弱引用
WeakHashMap$Entry.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private  static  class  Entry <K ,V > extends  WeakReference <Object > implements  Map .Entry <K ,V >     V value;     final  int  hash;     Entry<K,V> next;     Entry(Object key, V value, ReferenceQueue<Object> queue, int  hash, Entry<K,V> next) {                  super (key, queue);                  this .value = value;         this .hash  = hash;         this .next  = next;     }     public  K getKey ()                    return  (K) WeakHashMap.unmaskNull(get());     }      } 
Key被回收后,Entry对象还在,相当于在Map结构中有很多key变成了null值,此时外界通过原来的Key已经无法查出数据put,get,size都要获取底层存储数组,而这里会预先清理一遍
WeakHashMap.java 1 2 3 4 5 6 7 8 9 10 public  int  size ()      if  (size == 0 )         return  0 ;     expungeStaleEntries();     return  size; } private  Entry<K,V>[] getTable() {    expungeStaleEntries();     return  table; } 
清理的过程就是遍历引用队列,然后查找到底层数组,再从链表中移除
WeakHashMap.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private  void  expungeStaleEntries ()      for  (Object x; (x = queue.poll()) != null ; ) {                  synchronized  (queue) {             @SuppressWarnings ("unchecked" )             Entry<K,V> e = (Entry<K,V>) x;             int  i = indexFor(e.hash, table.length);             Entry<K,V> prev = table[i];             Entry<K,V> p = prev;             while  (p != null ) {                 Entry<K,V> next = p.next;                                  if  (p == e) {                                          if  (prev == e)                         table[i] = next;                     else                          prev.next = next;                                                               e.value = null ;                      size--;                     break ;                 }                 prev = p;                 p = next;             }         }     } }