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

  • 时间:
  • 浏览:1

关于强引用、软引用、弱引用、幻象引用的区别,在好多好多 公司的面试题中时不时出先,是因为许多小伙伴觉得你你这人知识点比较冷门,但觉得当一帮人 儿在开发中时不时用到,如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<Object> sf = new SoftReference<Object>(obj);
obj = null;
//有过前会返回null
sf.get(); 

通过上边的代码还还要看出sf是对obj的另另一个 软引用,当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的判断,是因为会出先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)

幻象引用,全部否有被说成是虚引用或疾速引用。幻象引用暂且会决定对象的生命周期。即是因为另另一个 对象仅持有虚引用,就至少这样 任何引用一样,在任何刚刚都是因为被垃圾回收器回收。可不可以 通过它访问对象,幻象引用仅仅是提供了五种生活确保对象被finalize刚刚,做许多事情的机制(如做所谓的Post-Mortem清理机制),全部否有人利用幻象引用监控对象的创建和销毁。

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

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

5.生存还是死亡

通过上边对五种生活引用类型的分析,你是因为发现许多对象即使不可达,但也暂且是“非死不可”的,你你这人刚刚它们暂时处在“缓刑”阶段,要真正敲定另另一个 对象死亡,至少要经历两次标记过程是因为对象在进行可达性分析后发现这样 与GC Roots相连接的引用链,那它是因为被第一次标记因此进行一次筛选,筛选的条件是此对象否有有必要执行finalize()最好的方式。当对象这样 覆盖finalize()最好的方式,是因为finalize()最好的方式是因为被虚拟机调用过,虚拟机将你你这人种生活情况都视为“这样 必要执行”。

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

任何另另一个 对象的finalize()最好的方式都只会被系统自动调用一次,是因为对象面临下一次回收,它的finalize()最好的方式不想被再次执行。

6.总结

对象的可达性是JVM垃圾埋点器决定怎样防止对象的另另一个 重要考虑指标

所有引用类型全部否有抽象类java.lang.ref.Reference的子类,子类里提供了get()最好的方式。通过上边的分析中还还要得知,除了幻象引用(是因为get永远返回null),是因为对象还这样 被销毁,都还还要通过get最好的方式获取原有对象。觉得有个非常关键的注意点,利用软引用和弱引用,当一帮人 儿还还要将访问到的对象,重新指向强引用,也要是人为的改变了对象的可达性情况。好多好多 对于软引用、弱引用类式,垃圾埋点器是因为会处在二次确认的问提,以确保处在弱引用情况的对象这样 改变为强引用。

因此有个问提,是因为当一帮人 儿错误的保持了强引用(比如,赋值给了static变量),这样 对象是因为就这样 是因为变回类式弱引用的可达性情况了,就会产生内存泄露。好多好多 ,检查弱引用指向对象否有被垃圾埋点,也是诊断否有有特定内存泄露的另另一个 思路,当一帮人 儿的框架使用到弱引用又怀疑有内存泄露,就还还要从你你这人厚度检查。

对于软引用、弱引用、幻象引用还还要配合引用队列(ReferenceQueue)来使用,有点儿是幻象引用,get最好的方式只返回null,是因为再不指定引用队列,基本就这样 任何意义了。

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

热门阅读:

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

参考

《深入理解Java虚拟机》

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