【JVM从小白学成大佬】3.深入解析强引用、软引用、弱引用、幻象引用

  • 时间:
  • 浏览:0

关于强引用、软引用、弱引用、幻象引用的区别,在所以公司的面试题中有有2个 劲有有2个 劲老出,愿因有些小伙伴觉得你并否是知识点比较冷门,但觉得大伙在开发中有有2个 劲用到,如new一有有有2个 对象的我你要怎么让强引用的应用。

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

这并否是 应用主要的区别体现在对象不同的可达性请况和对垃圾下发的影响,大伙之间的可达性请况可不必必 参看下图:

1.强引用(strong reference)

强引用怎么让大伙最常见的普通对象引用(如new 一有有有2个 对象),倘若还有强引用指向一有有有2个 对象,就表明此对象还“活着”。在强引用手中,即使JVM内存空间缺陷,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),让程序异常终止,怎么让会靠回收强引用对象来除理内存缺陷的问题报告 。对于一有有有2个 普通的对象,愿因越来越 有些的引用关系,倘若超过了引用的作用域愿因显式地将相应(强)引用赋值为null,就愿因此对象可不必必 被垃圾下发了。但要注意的是,并一定会赋值为null后就立马被垃圾回收,具体的回收时机还是要看垃圾下发策略的。

如Object obj = new Object();

2.软引用(soft reference)

软引用相对强引用要弱化有些,**可不必必 让对象豁免有些垃圾下发。当内存空间足够的我你要,垃圾回收器不必回收它。**越来越 当JVM认定内存空间缺陷时才会去回收软引用指向的对象。JVM会确保在抛出OOM前清理软引用指向的对象,怎么让JVM是很聪明的,会尽愿因优先回收长时间闲置不必的软引用指向的对象,对有有哪些刚构建的或刚使用过的软引用指向的对象尽愿因的保留。基于软引用的有有哪些形状,软引用可不必必 用来实现所以内存敏感点的缓存场景,即愿因内存还有空闲,可不必必 暂时缓存有些业务场景所需的数据,当内存缺陷时就可不必必 清理掉,等底下再时要时,可不必必 重新获取并再次缓存。一有有有有2个 就确保在使用缓存提升性能的同時 ,不必愿因耗尽内存。

软引用通常可不必必 和一有有有2个 引用队列(ReferenceQueue)联合使用,愿因弱引用所引用的对象被垃圾回收,java虚拟机就会把你并否是软引用加入到与之关联的引用队列中。

Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
//有我你要会返回null
sf.get(); 

通过底下的代码可不必必 看出sf是对obj的一有有有2个 软引用,当sf对象还越来越 被销毁前,sf.get()可不必必 获取到你并否是对象,愿因已被销毁,则返回null。

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

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

在使用软引用的我你要时要检查引用否是是为null。愿因垃圾下发器愿因在任意时刻回收软引用,愿因不做否是是null的判断,愿因会有有2个 劲老出NullPointerException的异常。

总的来说,软引用是用来描述有些还有用但不言而喻必需的对象。对于软引用关联着的对象,在系统将要居于内存溢出异常我你要,愿因把有有哪些对象列进回收范围之中进行第二次回收。愿因这次回收还越来越 足够的内存,才会抛出内存溢出异常。

3.弱引用(weak reference)

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

基于弱引用的有有哪些形状,弱引用同样可不必必 应用在所以时要缓存的场景。

Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
//有我你要会返回null
wf.get();
//返回否是是被垃圾回收器标记为即将回收的垃圾
wf.isEnQueued();

4.幻象引用(phantom reference)

幻象引用,一定会被说成是虚引用或暗影引用。幻象引用不言而喻会决定对象的生命周期。即愿因一有有有2个 对象仅持有虚引用,就要花费越来越 任何引用一样,在任何我你要都愿因被垃圾回收器回收。越来越 通过它访问对象,幻象引用仅仅是提供了并否是 确保对象被finalize我你要,做有些事情的机制(如做所谓的Post-Mortem清理机制),一定会人利用幻象引用监控对象的创建和销毁。

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

幻象引用的get最好的办法永远返回null,主要用于检查对象否是愿因从内存中删除。

5.生存还是死亡

通过底下对并否是 引用类型的分析,你愿因发现有些对象即使不可达,但所以言而喻是“非死不可”的,你并否是我你要它们暂时居于“缓刑”阶段,要真正发表声明一有有有2个 对象死亡,要花费要经历两次标记过程愿因对象在进行可达性分析后发现越来越 与GC Roots相连接的引用链,那它愿因被第一次标记怎么让进行一次筛选,筛选的条件是此对象否是是有必要执行finalize()最好的办法。当对象越来越 覆盖finalize()最好的办法,愿因finalize()最好的办法愿因被虚拟机调用过,虚拟机将这并否是 请况都视为“越来越 必要执行”。

愿因你并否是对象被判定为有必要执行finalize()最好的办法,越来越 你并否是对象愿因放置在一有有有2个 叫做F-Queue的队列之中,并在稍后被一有有有2个 由虚拟机自动建立的、低优先级的Finalizer程序去执行它。这里所谓的“执行”是指虚拟愿因触发你并否是最好的办法,但不言而喻承诺会等待英文它运行结速,一有有有有2个 做的愿因是,愿因一有有有2个 对象在finalize()最好的办法中执行缓慢,愿因居于了死循环(更极端的请况),将很愿因会愿因F-Queue队列中有些对象永久居于等待英文,甚至愿因整个内存回收系统奔溃。finalize()最好的办法是对象逃脱死亡命运的最后一次愿因,稍后GC将对F-Queue中的对象进行第二次小规模的标记,愿因对象要在finalize()中成功拯救我本人——倘若重新与引用链上的任何一有有有2个 对象建立关联即可。譬如把我本人(this关键字)赋值给某个类变量愿因对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;愿因对象这我你要还越来越 逃脱,那基本上它就真的被回收了。

任何一有有有2个 对象的finalize()最好的办法都只会被系统自动调用一次,愿因对象面临下一次回收,它的finalize()最好的办法不必被再次执行。

6.总结

对象的可达性是JVM垃圾下发器决定怎么除理对象的一有有有2个 重要考虑指标

所有引用类型一定会抽象类java.lang.ref.Reference的子类,子类里提供了get()最好的办法。通过底下的分析中可不必必 得知,除了幻象引用(愿因get永远返回null),愿因对象还越来越 被销毁,都可不必必 通过get最好的办法获取原有对象。觉得有个非常关键的注意点,利用软引用和弱引用,大伙可不必必 将访问到的对象,重新指向强引用,也怎么让人为的改变了对象的可达性请况。所以对于软引用、弱引用同类,垃圾下发器愿因会居于二次确认的问题报告 ,以确保居于弱引用请况的对象越来越 改变为强引用。

怎么让有个问题报告 ,愿因大伙错误的保持了强引用(比如,赋值给了static变量),越来越 对象愿因就越来越 愿因变回同类弱引用的可达性请况了,就会产生内存泄露。所以,检查弱引用指向对象否是是被垃圾下发,也是诊断否是是有特定内存泄露的一有有有2个 思路,大伙的框架使用到弱引用又怀疑有内存泄露,就可不必必 从你并否是高度检查。

对于软引用、弱引用、幻象引用可不必必 配合引用队列(ReferenceQueue)来使用,怪怪的是幻象引用,get最好的办法只返回null,愿因再不指定引用队列,基本就越来越 任何意义了。

底下分析了并否是 引用类型的使用,熟悉这几种应用类型对深入理解JVM也大有裨益。

热门阅读: 【JVM从小白学成大佬】1.开篇 【JVM从小白学成大佬】2.Java虚拟机运行时数据区

参考

《深入理解Java虚拟机》

http://www.kdgregory.com/index.php?page=java.refobj