资讯专栏INFORMATION COLUMN

深入解析强引用、软引用、弱引用、幻象引用

Bmob / 3298人阅读

摘要:弱引用与软引用最大的区别就是弱引用比软引用的生命周期更短暂。所以对于软引用弱引用之类,垃圾收集器可能会存在二次确认的问题,以确保处于弱引用状态的对象没有改变为强引用。

关于强引用、软引用、弱引用、幻象引用的区别,在一些大公司的面试题中经常出现,可能有些小伙伴觉得这个知识点比较冷门,但其实大家在开发中经常用到,如new一个对象的时候就是强引用的应用。

在java语言中,除了原始数据类型(boolean、byte、short、char、int、float、double、long)的变量,其他所有都是所谓的引用类型,指向各种不同的对象。理解这些引用的区别,对于掌握java对象生命周期和JVM内部相关机制非常有帮助。也有助于更深刻的理解底层对象生命周期、垃圾收集机制等,对设计可靠的缓存框架、诊断应用OOM等问题也大有裨益。

这四种应用主要的区别体现在对象不同的可达性状态和对垃圾收集的影响,他们之间的可达性状态可以参看下图:

1.强引用(strong reference)

强引用就是我们最常见的普通对象引用(如new 一个对象),只要还有强引用指向一个对象,就表明此对象还“活着”。在强引用面前,即使JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),让程序异常终止,也不会靠回收强引用对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为null,就意味着此对象可以被垃圾收集了。但要注意的是,并不是赋值为null后就立马被垃圾回收,具体的回收时机还是要看垃圾收集策略的。

如Object obj = new Object();

2.软引用(soft reference)

软引用相对强引用要弱化一些,可以让对象豁免一些垃圾收集。当内存空间足够的时候,垃圾回收器不会回收它。只有当JVM认定内存空间不足时才会去回收软引用指向的对象。JVM会确保在抛出OOM前清理软引用指向的对象,而且JVM是很聪明的,会尽可能优先回收长时间闲置不用的软引用指向的对象,对那些刚构建的或刚使用过的软引用指向的对象尽可能的保留。基于软引用的这些特性,软引用可以用来实现很多内存敏感点的缓存场景,即如果内存还有空闲,可以暂时缓存一些业务场景所需的数据,当内存不足时就可以清理掉,等后面再需要时,可以重新获取并再次缓存。这样就确保在使用缓存提升性能的同时,不会导致耗尽内存。

软引用通常可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,java虚拟机就会把这个软引用加入到与之关联的引用队列中。

Object obj = new Object();
SoftReference sf = new SoftReference(obj);
obj = null;
//有时候会返回null
sf.get(); 

通过上面的代码可以看出sf是对obj的一个软引用,当sf对象还没有被销毁前,sf.get()可以获取到这个对象,如果已被销毁,则返回null。

正确使用软引用的示例代码如下:

SoftReference> ref = new SoftReference>(new LinkedList());
 
// somewhere else in your code, you create a Foo that you want to add to the list
List list = ref.get();
if (list != null)
{
    list.add(foo);
}
else
{
    // list is gone; do whatever is appropriate
} 

在使用软引用的时候必须检查引用是否为null。因为垃圾收集器可能在任意时刻回收软引用,如果不做是否null的判断,可能会出现NullPointerException的异常。

3.弱引用(weak reference)

弱引用指向的对象是一种十分临近finalize状态的情况,当弱引用被清除的时候,就符合finalize的条件了。弱引用与软引用最大的区别就是弱引用比软引用的生命周期更短暂。垃圾回收器会扫描它所管辖的内存区域的过程中,只要发现弱引用的对象,不管内存空间是否有空闲,都会立刻回收它。如同前面我说过的,具体的回收时机还是要看垃圾回收策略的,因此那些弱引用的对象并不是说只要达到弱引用状态就会立马被回收。

基于弱引用的这些特性,弱引用同样可以应用在很多需要缓存的场景。

Object obj = new Object();
WeakReference wf = new WeakReference(obj);
obj = null;
//有时候会返回null
wf.get();
//返回是否被垃圾回收器标记为即将回收的垃圾
wf.isEnQueued();
4.幻象引用(phantom reference)

幻象引用,也有被说成是虚引用或幽灵引用。幻象引用并不会决定对象的生命周期。即如果一个对象仅持有虚引用,就相当于没有任何引用一样,在任何时候都可能被垃圾回收器回收。不能通过它访问对象,幻象引用仅仅是提供了一种确保对象被finalize以后,做某些事情的机制(如做所谓的Post-Mortem清理机制),也有人利用幻象引用监控对象的创建和销毁。

Object obj = new Object();
PhantomReference pf = new PhantomReference(obj);
obj=null;
//永远返回null
pf.get();
//返回是否从内存中已经删除
pf.isEnQueued(); 

 
幻象引用的get方法永远返回null,主要用于检查对象是否已经从内存中删除。

通过上面对四种引用类型的分析,你可能发现对象的可达性是JVM垃圾收集器决定如何处理对象的一个重要考虑指标。

所有引用类型都是抽象类java.lang.ref.Reference的子类,子类里提供了get()方法。通过上面的分析中可以得知,除了幻象引用(因为get永远返回null),如果对象还没有被销毁,都可以通过get方法获取原有对象。其实有个非常关键的注意点,利用软引用和弱引用,我们可以将访问到的对象,重新指向强引用,也就是人为的改变了对象的可达性状态。所以对于软引用、弱引用之类,垃圾收集器可能会存在二次确认的问题,以确保处于弱引用状态的对象没有改变为强引用。

但是有个问题,如果我们错误的保持了强引用(比如,赋值给了static变量),那么对象可能就没有机会变回类似弱引用的可达性状态了,就会产生内存泄露。所以,检查弱引用指向对象是否被垃圾收集,也是诊断是否有特定内存泄露的一个思路,我们的框架使用到弱引用又怀疑有内存泄露,就可以从这个角度检查。

对于软引用、弱引用、幻象引用可以配合引用队列(ReferenceQueue)来使用,特别是幻象引用,get方法只返回null,如果再不指定引用队列,基本就没有任何意义了。

上面分析了四种引用类型的使用,熟悉这几种应用类型对深入理解JVM也大有裨益。

参考:

http://www.kdgregory.com/inde...

极客时间《Java核心技术36讲》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75672.html

相关文章

  • 金三银四面试季节之Java 核心面试技术点 - JVM 小结

    摘要:直接对栈的操作只有两个,就是对栈帧的压栈和出栈。中将永久代移除,同时增加元数据区。在中,本地方法栈和虚拟机栈是在同一块儿区域,这完全取决于技术实现的决定,并未在规范中强制。 原文:https://github.com/linsheng97... 描述一下 JVM 的内存区域 程序计数器(PC,Program Counter Register)。在 JVM 规范中,每个线程都有它自己的...

    XGBCCC 评论0 收藏0
  • Java中的四种引用引用引用引用、虚引用

    摘要:在之后,对引用的概念进行了扩充,将引用分为强引用软引用弱引用虚引用种,这种引用强度依次逐渐减弱。软引用是用来描述一些还有用但并非必需的对象。虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。 以下内容摘自《深入理解Java虚拟机 JVM高级特性与最佳实践》第2版,强烈推荐没有看过的同学阅读,读完的感觉就是原来学的都是些什么瘠薄东西(╯‵□′)╯︵┴─┴ 在JDK1.2以前,Ja...

    wwolf 评论0 收藏0
  • 几分钟理解 Jdk - Reference

    摘要:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。在之后提供了类来实现虚引用参考深入理解虚拟机 GC $TODO$ 一个对象的生命周期 一个对象的生命周期从它被创建开始,此时虚拟机会给它置一个内部标识finalizable,当 GC 到达某一个安全点并检验该...

    JohnLui 评论0 收藏0
  • 引用都答不上,凭什么说你是Java服务端开发

    摘要:弱引用弱引用比软引用更弱,被弱引用关联的对象只能存活到发生下一次垃圾回收之前,也就是说当发生时,无论当前内存是否足够,都会被回收掉。这是最终的状态,不能再变为其它状态。如下图所示对象都是可被回收的。 【干货点】看完该篇文章,就基本可以解答面试热点【谈谈对Java中几种引用的理解】了。 大家都知道我公众号的副业是 showImg(https://segmentfault.com/img/...

    mozillazg 评论0 收藏0
  • 深入理解虚拟机之垃圾回收

    摘要:深入理解虚拟机高级特性与最佳实践第二版读书笔记与常见面试题总结上篇文章传送门深入理解虚拟机之内存区域本节常见面试题推荐带着问题阅读,问题答案在文中都有提到如何判断对象是否死亡两种方法。虚引用主要用来跟踪对象被垃圾回收的活动。 《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版》读书笔记与常见面试题总结 上篇文章传送门: 深入理解虚拟机之Java内存区域 本节常见面试题(推荐带着...

    IamDLY 评论0 收藏0

发表评论

0条评论

Bmob

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<