文章目录
- 强引用
- 弱引用
- 软引用
- 虚引用
将引用之前首先让我们一起回顾一下
java对象的生命周期
强引用
在实际开发场景中,我们一般使用的都是强引用,只要强引用存在,垃圾回收即使OOM也不会回收,知道强引用释放以后,对象才会被释放掉,可以显示地将引用赋值为null,这样的话,JVM会在合适的时间回收该对象。
以下是测试:
public void method() {Object o = new Object();Object[] os = new Object[800000];System.out.println(os.length);}@Testpublic void srongReference(){method();}
在method方法没有结束之前,method中定义的局部变量的对象是不会被回收,method结束后会在适合GC。
回收测试:
@Testpublic void strongReference() throws InterruptedException {Thread.sleep(40 * 1000);System.out.println("加载");method();Object o = new Object();Object[] os = new Object[800000];System.out.println("判断是否回收");Thread.sleep(20 * 1000);o = null;os = null;System.gc();System.out.println("强制回收");Thread.sleep(100 * 1000);}
通过 jconsole监控内存变化,发现当强引用关系解除以后,强制GC的时候,对象会被回收掉!!!
弱引用
引用是用来描述非必须对象的,当JVM进行垃圾回收时候,无论内存是否充足,都会回收。
@Testpublic void weakReference() {
// ArrayList<Person> ps = new ArrayList<>();//list存储的对象引用也是强引用关系
// ps.add(person);WeakReference<Object> wf = new WeakReference<>(new Person("weijie", 25));System.out.println(wf.get());System.out.println(wf.isEnqueued());System.gc();System.out.println(wf.get());System.out.println(wf.isEnqueued());}
由控制台输可以看出,只要是弱引用,只要发生GC对象会被回收。
@Testpublic void weakReference() {Person person = new Person("weijie", 25);ArrayList<Person> ps = new ArrayList<>();//list存储的对象引用也是强引用关系ps.add(person);WeakReference<Object> wf = new WeakReference<>(person);System.out.println(wf.get());System.out.println(wf.isEnqueued());System.gc();System.out.println(wf.get());System.out.println(wf.isEnqueued());}
由上可看出由于list导致对象存在强引用关系,此时加上弱引用的话对象也不会被回收,需要手动将person=null 接触强引用关系以后,对象才会GC时候回收
软引用
用来描述一些有用但并不是必须的对象,对于软引用关联的对象,只有在内存不足的时候JVM才会回收该对象,这一点可以很好解决OOM问题,这个特性很适合用来实现缓存:网页缓存、图片缓存等。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。
@Testpublic void softReference() {SoftReferenceCache<Integer, Person> referenceCache = new SoftReferenceCache<>();referenceCache.put(0, new Person("weijie", 24));System.gc();System.out.println(referenceCache.get(0));}
虚引用
虚引用:垃圾回收时回收,无法通过引用取到对象值PhantomReference 唯一的用处就是跟踪 referent 何时被 enqueue(入队列) 到 ReferenceQueue 中虚引用主要用来跟踪对象被垃圾回收的活动。
虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用, 来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列, 那么就可以在所引用的对象的内存被回收之前采取必要的行动。
@Testpublic void phantomReference(){Person person = new Person("weijie", 24);ReferenceQueue<Person> referenceQueue = new ReferenceQueue<Person>();PhantomReference<Person> personPhantomReference = new PhantomReference<Person>(person, referenceQueue);System.out.println(referenceQueue.poll());System.out.println(personPhantomReference.get());//判断对象是否被标记回收System.out.println(personPhantomReference.enqueue());person = null;System.out.println(personPhantomReference.get());System.out.println(personPhantomReference.enqueue());}
虚引用打印的值永远为null,唯一用处就是显示enqueue(入队列)