Java引入类型
强引用:当内存不足的时候,JVM宁可出现OutOfMemoryError,也不会将内存回收。
强引用是JVM默认的支持模式,即:在引用期间,如果该堆内存被栈内存所指向,那么该对象无法被GC回收,如果出现内存空间不足,就会抛出 “OutOfMemoryError”。
public static void main(String[] args) { Object o = new Object(); // 强引用 Object ref = o; // 引用传递 o = null; // 断开一个引用 System.gc(); // 手动垃圾回收 System.out.println(ref); } 输出: java.lang.Object@3cd1a2f1
软引用:内存不足的时候,进行对象的回收,往往用于高速缓存。
在许多的开源组件之中,往往会使用软引用作为缓存组件出现,最大的特点就是:内存空间充足时不回收,内存空间不足时回收。
// 内存充足 public static void main(String[] args) { Object o = new Object(); SoftReference softReference = new SoftReference(o); // 软引用 o = null; // 使new Object() 只维护一个软引用 System.gc(); // 垃圾回收 System.out.println("软引用:" + softReference.get()); } 输出: 软引用:java.lang.Object@3cd1a2f1 /******************************************************/ // 内存不足 public static void main(String[] args) { Object o = new Object(); SoftReference softReference = new SoftReference(o); // 软引用 o = null; // 使new Object() 只维护一个软引用 // 创造大量垃圾,触发GC String str = "showSoftRef"; try { for (int i = 0; i < 100; i++) { str += str; str.intern(); } } catch (Throwable e) { } System.out.println("软引用:" + softReference.get()); } 输出: 软引用:null
弱引用:不管内存是否紧张,只要有GC处理,就会被回收。弱引用需要使用的是Map接口的子类:java.util.WeakHashMap。
public static void main(String[] args) { String hello = new String("hello"); String world = new String("world"); // 弱引用 Map<String, String> map = new WeakHashMap<String, String>(); map.put(hello, world); System.out.println(map); hello = null; //断开强引用 System.out.println(map); System.gc(); // 垃圾回收 System.out.println(map); } 输出: {hello=world} {hello=world} {} /******************************************************/ 把上面的WeakHashMap替换成HashMap,输出结果为: {hello=world} {hello=world} {hello=world} // 因为:HashMap是强引用,不会被回收 // 为什么项目中不用WeakHashMap而频繁使用HashMap呢? // 如果在项目中使用WeakHashMap,当一条线程在取数据的时候,另外一条线程在进行GC,这个容易丢失数据。 /******************************************************/ public static void main(String[] args) { Object o = new Object(); WeakReference softReference = new WeakReference(o); // 弱引用 o = null; // 使new Object() 只维护一个弱引用 System.gc(); // 垃圾回收 System.out.println("弱引用:" + softReference.get()); } 输出: 弱引用:null
幽灵引用(虚引用):永远无法从这个引用中取数据。
所有保存在幽灵引用中的数据都不会真正的保留。
public static void main(String[] args) throws InterruptedException { Object o = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); PhantomReference softReference = new PhantomReference(o, queue); // 幽灵引用 // 这里没有断开强引用 System.gc(); System.out.println(softReference.get()); System.out.println(queue.poll()); } 输出: null null
引用对列:保存准备被回收的对象。很多时候对象的回收扫描都要从根集合开始,那么对于整个GC而言,要想确定哪些对象可以被回收,就必须确定好引用的强度这个也就是所谓的引用路径设置。
如果现在要找到对象5,很明显:1 到 5 属于 “强+软”,2 到 5 属于 “强+弱”;软引用要比弱引用保存程度更强。这个时候对于对象的引用而言,如果要进行引用的关联判断,我们就必须找到强关联。为了避免非强引用对象带来的内存引用问题,所以提供引用队列的概念。
如果在创建软引用或者弱引用类型的时候使用引用队列的方式,那么这个对象被回收之后会自动保存在引用队列之中。
public static void main(String[] args) throws InterruptedException { Object o = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); // 引用队列 WeakReference softReference = new WeakReference(o, queue); // 弱引用 System.out.println(queue.poll()); o = null; // 断开强引用 System.gc(); Thread.sleep(100); // 等待对象被保存到引用队列中 System.out.println(queue.poll()); } 输出: null java.lang.ref.WeakReference@3cd1a2f1