1)引用出现的根源
引用出现的根源是由于GC内存回收的基本原理。GC回收本质上是回收对象。目前比较流行的回收算法是可达性分析算法。从GC roots开始安装一定的逻辑判断一个对象是否可达,不可达的话就说明这个对象已死。(除此之外另外一种常见的算法是引用计数法,但是这种算法有个问题就是不能解决相互引用的问题)。
基于此Java向用户提供了四种可用的引用(强引用、软引用、弱引用、幻象引用),同时还提供了一种不可被使用的引用(FinalReference)这个引用是和析构函数相关的。
2)四种引用的概念,特点,使用场景及区别
①强引用
我们平常典型代码Object obj=new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显示的将相应引用赋值为null,就是可以被垃圾收集了,具体回收时机还是要看垃圾收集策略。
应用场景:项目中到处都在使用
②软引用
软引用通过SoftReference类来实现。软引用的生命周期比强引用短一些。只有当JVM认为内存不足时,才会去试图回收软引用指向的对象:即JVM会确保在抛出OutOfMemoryError之前,清理软引用指向的对象。软引用可以和引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。
应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时可以清理掉,这样就保证了使用缓存的同时,不会耗尽内存。
③弱引用
弱引用通过WeakReference类来实现。弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
应用场景: 弱引用同样可用于内存敏感的缓存。
④幻象引用
幻象引用也叫虚引用,通过PhantomReference类来实现。无法通过虚引用访问对象的属性或函数。幻象引用仅仅是提供了一种确保对象被finalize之后,做某些事情的机制。如果一个对象仅持有虚引用,那么它和没有任何引用一样。在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列(ReferenceQueue)联合使用。 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
ReferenceQueue queue=new ReferenceQueue();
PhantomReference pr=new PhantomReference(object,queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用对列,那么就可以在所引用的对象的内存被回收之前采取一些程序行动。
应用场景: 可用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集齐回收之前收到一个系统通知。
3)扩展
这是一个评论者提供的一篇文章,读读它去理解这几个reference的概念和作用,很有帮助