引用的概念
-
引用可以描述为变量和具体对象之间的关联关系
//Object类型的变量obj引用了一个Object类型的对象 Object obj = new Object(); //String类型的变量str引用了一个String类型的对象 String str = new String("xxx"); //引用关系建立之后 就可以通过变量操作对象了
-
java中的引用类型
- 强引用
- 软引用
- 弱引用
- 虚引用
引用强度是:强引用>软引用>弱引用>虚引用
这几种引用关系扩展了对象只有“被引用”和“未引用”两种引用关系。
强引用
-
普通的代码中的引用关系就是强引用
Object obj = new Object(); String str = new String("xxx");
一个对象只要还存在一个强引用与之关联,任何情况下都不会被GC回收。
如果在内存不足的情况下继续创建对象,JVM宁可抛出OOM(OutOfMemory)异常,也不会回收强引用对象。
可以手动断开这种强引用关系
obj = null; str = null; //此时new Object() 和 new String("xxx")对象没有了强引用关系 //将会在适当的时机被GC回收
软引用
-
特点
- 软引用用来描述一些有用但不是必需的对象的引用关系。
- java中使用java.lang.ref.SoftReference类来表示软引用关系
- 软引用关联的对象只有在内存不足时才会被GC回收。这个特点可以用来解决OOM问题。
- 可以使用软引用来实现本地缓存:如文件缓存,图片缓存等。
-
代码实现
//创建一个软引用对象 SoftReference<String> softReference = new SoftReference<>(new String("softReference Test")); //调用GC System.gc(); //内存充足时 会打印字符串 //当内存不足时 会打印null System.out.println(softReference.get());
弱引用
-
特点
- 弱引用也是用来描述非必需对象的
- java中使用java.lang.ref.WeakReference类来表示
- 弱引用关联的对象在GC调用时都会被回收,不论当前内存是否充足。
-
代码实现
//创建一个弱引用对象 WeakReference<String> weakReference = new WeakReference<>(new String("weakReference Test")); //打印字符串 System.out.println(weakReference.get()); //调用GC System.gc(); //打印null System.out.println(weakReference.get());
虚引用
-
特点
-
虚引用不会影响对象的生命周期,即跟没引用对象一样
-
在java中用java.lang.ref.PhantomReference类表示
-
虚引用关联的对象随时会被回收
-
虚引用只能和一个关联队列一起使用
-
查看PhantomReference类源码
public class PhantomReference<T> extends Reference<T> { //get方法直接返回null public T get() { return null; } //构造方法必须传一个ReferenceQueue 对象 public PhantomReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } }
-
-
代码实现
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); //创建一个虚引用对象 PhantomReference<String> phantomReference = new PhantomReference<>(new String("PhantomReference Test"),referenceQueue); //打印null System.out.println(phantomReference.get()); //调用GC System.gc(); //打印null System.out.println(phantomReference.get());
ReferenceQueue的使用
-
软引用、弱引用、虚引用可以关联一个ReferenceQueue对象使用
-
当上面几种引用关系的对象被GC回收时,就会把相应的包装类放入到ReferenceQueue。
比如下面代码
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); //创建一个弱引用对象 WeakReference<String> weakReference = new WeakReference<>(new String("PhantomReference Test"),referenceQueue); //当new String("PhantomReference Test")这个对象被回收时 //weakReference这个对象会放入到referenceQueue中
-
可以从ReferenceQueue中取出相应的对象信息,做一些对象被回收后的处理。
-
模拟ReferenceQueue的使用。以WeakReference类型为列。SoftReference和PhantomReference一样。
在主线程中创建多个WeakReference关联的对象,并调用GC。在一个守护线程中查看被回收对象的封装对象的信息
static ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); public static void main(String[] args) { Thread thread = new Thread(()->{ int cnt = 1; while (true){ try { Reference reference = referenceQueue.remove(); System.out.println("第"+ (cnt++) +"此循环,"+reference+":被回收!!!"); } catch (InterruptedException e) { e.printStackTrace(); } //等待10毫秒 try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }); //设置线程为守护线程 主线程结束后该线程自动结束 thread.setDaemon(true); thread.start(); //创建WeakReference引用对象 并调用GC回收 for(int i = 0;i< 100;i++){ WeakReference<String> weakReference = new WeakReference<>(new String("txx"),referenceQueue); System.gc(); } //等待10秒 让后台线程执行完毕 try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } }