本文简单介绍下Java的四大引用:强引用,软引用,弱引用,虚引用;
四大引用的架构关系
强引用(Reference),软引用(SoftReference) ,弱引用 (WeakReference) ,虚引用(PhantomReference)
强引用
强引用是我们工作中最常见的普通对象引用,只要还有强引用指向一个对象,就能代表对象还存活着,垃圾收集器不会清理这种对象。Java中最常见的就是强引用,把一个对象赋值一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即该对象以后永远都不会被JVM回收,因此强引用是造成Java内存泄漏的主要原因之一。
当内存不足时,JVM开始垃圾回收,对于强引用的对象,计算是出现OOM也不会将对象进行回收的。
对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应的强引用赋值为null,一般认为就是可以被垃圾收集的,当然具体回收时机还是要看垃圾收集策略。
示例:
我们可以看到object2对象没有被垃圾回收掉。
软引用
我们在上面说到强引用哪怕是内部不足也不会将垃圾回收,然软引用则是当内存不足的时候会被垃圾回收,内存足够的情况下,就不会回收。
软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference类实现,可以让对象豁免一些垃圾收集。对于软引用的对象来说,当系统的内存充足时,它不会被回收,当系统内存不足时,它会被回收。
软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收!
我们可以看到object对象和软引用get的对象内存地址是一样的,当内存充足的情况下,软引用并没有被垃圾回收掉,我们配置下运行的内存大小后,再看下运行结果
我们看到配置5m的内存大小,然后在代码中模拟创建10m的大对象,当内存不足够的时候,垃圾回收会将软引用进行回收。
弱引用
弱引用需要用java.lang.ref.WeakReference类来实现,它比软引用的生存期更短,对于弱引用的对象来说,只要垃圾回收机制一运行,不管jvm的内存空间是否足够,都会回收该对象的占用的内存。
我们看到弱引用内存足够的情况,gc后弱引用就会被回收。
虚引用
虚引用需要java.lang.ref.PhantomReference类来实现。
顾名思义,就是形同虚设,与其他几种引用不同,虚引用并不会决定对象的生命周期,如果一个对象仅仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。
虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅是提供了一个确保对象被finalize以后,做某些事情的机制。PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收机制。
换句话说,设置虚引用关联的唯一目的就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。java允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
ReferenceQueue引用队列在对象被回收前需要被引用队列保存下;
当虚引用被回收前,引用队列中是没有数据的,调用gc后,可以看到引用队列会保存下回收的对象。
java提供了四种引用类型,在垃圾回收的时候,都有各自的特点。ReferenceQueue是用来配合引用工作的,虚引用一定要联合引用队列使用,其他三种没有引入引用队列也一样可以运行。
创建引用的时候可以指定关联的队列,当GC释放对象内存的时候,会将引用加入引用队列,如果程序发现某虚引用已经加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动,这相当于一种通知机制。当关联引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。通过这种方式,JVM允许我们在对象被销毁后,做一些我们想做的事情。