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

  • 时间:
  • 浏览:5

关于强引用、软引用、弱引用、幻象引用的区别,在什么都公司的面试题中老是再次再次出现,不可能 或多或少小伙伴嘴笨 或多或少知识点比较冷门,但嘴笨 大伙儿在开发中老是用到,如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