面试经典题:强引用、软引用、弱引用、幻引用有什么区别?
典型回答:
不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和垃圾收集的影响。
所谓强引用(strong Reference),就是我们最常见的对象引用,只要还有强引用指向一个对象,就能表明对象还“活着“,垃圾收集器不会碰这种现象。对于一个普通的对象,如果没有其它的引用关系,只要超出了引用的作用域或者式的将相应的(强)引用赋值为
null
,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾回收策略。软引用(SoftReference),是一种相对于强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当JVM认为内存空间不足时,才会试图去回收软引用指向的对象。JVM会确保在抛出OutOfMemoryError之前,清理软引用指向的对象。软引用通常用来实现内存敏感的缓存,如果还有空闲内存,则暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时不会耗尽内存。
弱引用(WeakReference)并不能使对象豁免一些垃圾收集,仅仅提供一种访问弱引用状态下对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取的对象还在,就使用它,否则重现实例化。它同样是很多缓存的实现的选择。
对于幻象引用(虚引用),不能通过它访问对象,幻象引用仅仅是提供一种确保对象被finalize以后,做某些事情的机制,比如,通常用来做所谓的PostMortem清理机制,Java平台自身的Cleaner机制等,也有人利用幻象引用监控对象的创建与销毁。
概述
Java语言中,除了基本数据类型外,其它都是指向各类对象的的对象引用;
Java根据其生命周期的长短,将引用分为四种:强引用、软引用、弱引用、幻象引用
对象可达性状态图![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/27e794334d2d5e0b1decc89e689e4071.png)
Java定义的不同可达性级别(reachability level),具体如下:
- 强可达(Strongly Reachable),当一个对象可以有一个或多个线程可以不通过各种引用访问到的情况。比如,我们创建一个对象,呢么创建它的线程就是强可达。
- 软可达(softly Reachable),只能通过软引用才可以访问对象的状态。
- 弱可达(weakly Reachable),只能通过弱引用访问的状态,无法通过强引用或者软引用访问。这是十分接近finalize状态的时机,当弱引用被清理的时候就符合finalize的条件。
- 虚可达(Phantom Reachable),没有强、软、弱引用关联,并且finalize过了,只有幻象引用可以指向这个对象。
- 不可达(Unreachable),意味着对象可以被清理了。
一、强引用
特点:
1、平时典型的编码
Object obj = new Object()
中的obj
就是强引用,同过关键关键字new
创建的对象所关联的引用就是强引用。
2、当 JVM 内存空间不足,JVM 宁愿抛出OutOfMemoryError
运行时错误(OOM)是程序终止也不会靠随意回收具有强引用的的“存活”对像来解决内存不足问题。
3、对于一个普通对像,如果没有其它的引用关系,只要超过引用作用域或者显示地将相应的(强)引用赋值为null
,就可以被垃圾回收了,具体回收时机还是要看垃圾收集策略。
二、软引用
特点
1、软引用通过
SoftReference
类实现。软引用的生命周期比强引用短一些。
2、只有当JVM 认为内存不足时才会去试图回收软引用指向的对象:即JVM确保抛出OutOfMemoryError
之前清理软引用指向的对象。
3、软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所指向的对象被垃圾回收器回收,JVM会将这个软引用加入到与之相关联的引用队列。
4、可以调用ReferenceQueue
的pool()
方法来检查是否有它所关联的对象被回收,如果队列为空,将返回一个null
,否则该方法返回队列中队首的一个Reference
对象。
应用场景:
软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以展示保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时不会会耗尽内存。
三、软引用
特点:
1、弱引用通过
WorkReference
类来实现。软引用的生命周期比弱引用的要短。
2、在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现具有弱引用的对象,不管当前内存空间是否足够,都会回收它的内存。(由于垃圾回收器是一个优先级很低的线程,因此不一定很快回收回收弱引用的对象)。
3、弱引用可以和一个引用队列(ReferenceQueue)联合使用;如果弱引用所引用的对象被垃圾回收器回收,JVM就会把这个若引用加到与之相关联的引用队列中。
应用场景:
弱引用同样可以用于内存敏感的缓存。
四、幻象引用(虚引用)
特点:
1、幻象引用又叫虚引用,通过
PhantomReference
类来实现,无法通过虚引用访问对象的任何属性和方法。
2、幻象引用仅仅是提供了一种确保对象被finalize
以后做某些事的机制。
3、如果一个对象仅持有虚引用,那它和没有持有引用是一样的,在任何时候都可能被垃圾回收器回收。
4、虚引用必须和应用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现他还有虚引用,就会把这个虚引用加入到与之关联的引用对列中。
ReferenceQueue queue = new ReferenceQueue();
PhantomReference pr = new PhantomReference(Object queue);
5、程序可以判断通过判断引用队列中是否加入了虚引用来了解引用的对象是否要被垃圾回收。如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的的对象的内存被回收之前采取一些程序行动。
应用场景
1、可以用来追踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾回收器回收之前都会收到一条系统通知。
2、在静态内部类中经常使用虚引用。例如:一个类发送网络请求,承担callback的静态内部类则经常以虚引用的方式来保存外部类(宿主类)的引用,当外部列需要被JVM回收时不会因为网络请求没有及时相应,导致外部类无法被回收从而导致内存泄漏。