846f332ba82e63cc25b05d83a6d79bc0
Java 里的 JVM 引用

[TOC]

一、引用

1.1 分类:

根据对象的生命周期长短,可以分为:强引用、软引用、弱引用、幻象引用四种

1.2 get()

软引用和弱引用都可以通过其 get() 方法来获取原有对象,幻象引用通过 get() 得到的永远都为 null

1.3 ReferenceQueue

除了强引用,其余三种引用都可以与引用队列结合使用

那么当垃圾回收器准备回收一个被引用包装的对象时,该引用会被加入到关联的 ReferenceQueue中。程序可以通过判断引用队列中是否已经加入引用,从而了解被引用的对象是否被 GC 回收

它指定了引用队列的一些具体操作,简单地说就是链表实现的一些操作。除了强引用,其他都继承于此,通过该类约束引用的相关内容,便于和 GC 交互

1.4 Reference

类似一个链表结构,通过创建一个守护线程来执行对应引用的清除或Cleaner.clean,还有引用的入队操作(该操作需要在创建引用的时候就指定一个引用队列)

二、强引用

  • 产生:通过 new 关键字,此时对象强可达
  Object obj = new Object();
  • 特点:就算 JVM 内存空间不足也不会回收强引用类型的对象,只会抛出 OutOfMemoryError

  • 回收方式:将对象赋值为 null 或者对象超过了引用作用域,具体回收看垃圾收集的策略

三、软引用

  • 产生:通过 SoftReference 类,此时对象软可达
  Object obj = new Object();
  SoftReference<Object> sf = new SoftReference<Object>(obj);
  obj = null;  // 使对象只被软引用关联
  • 特点:生命周期比强引用短,JVM 内存不足时,且在抛出 OutOfMemoryError 前,会清理掉软引用指向的对象,意思就是 GC 检测到继续创建对象会导致 OOME ,此时就会进行一次内存回收,此时就会回收软引用指向的对象,防止 OOME

  • 原理:软引用会和一个引用队列(ReferenceQueue)联合使用,软引用所引用的对象被垃圾回收器回收后,JVM 会把这个软引用加入到与之关联的引用队列中,此时该对象处于软引用可达状态,之后我们可以调用 ReferenceQueue 的 poll() 方法来检查它所关联的对象回收状态。如果队列为空,poll() 返回一个 null,否则返回队列中第一个 Reference 对象

  • 使用场景:软引用通常用来实现内存敏感的缓存,意思是有空闲内存,暂时保留缓存,内存不足,就清楚,这样保证了缓存的同时,不会耗尽内存

    • 例1:图片缓存框架中(例如 Android 的 Glide框架),“内存缓存”中的图片上以这种引用来保存,JVM 在 OOM 之前可以回收这部分缓存
    • 例2:Java 的 ThreadLocal 与动态代理都是基于软引用实现

四、弱引用

  • 产生:通过 WeakReference 类,此时对象弱可达
  Object obj = new Object();
  WeakReference<Object> wf = new WeakReference<Object>(obj);
  obj = null;
  • 特点:生命周期比软引用短。在垃圾回收器线程在它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存,不过由于垃圾回收器上一个优先级很低的线程,因此不一定会很快回收弱引用的对象

  • 原理:弱引用可以和一个引用队列(ReferenceQueue)联合使用,弱引用所引用的对象被垃圾回收器回收后,JVM 就把该弱引用加入到与之关联的引用队列中

  • 使用场景:弱引用可以用于重要程度更低的,内存敏感的缓存

    • 例1,静态内部类中,经常使用弱引用
    • 例2,一个类发送网络请求,承担回调的静态内部类,经常以虚引用的方式来博阿存外部类的引用,从而,外部类需要被 JVM 回收时,不会因为网络请求没有及时返回,导致外部类不能回收,引起内存泄漏

五、幻象引用

  • 产生:通过 PhantomReference 类,此时对象幻象可达
  Object obj = new Object();
  PhantomReference<Object> pf = new PhantomReference<Object>(obj);
  obj = null;
  • 特点:无法通过幻象引用访问对象的任何属性或函数。幻象引用的作用就是提供一种确保对象被 finalize() 之后,可以做某些事情,如果一个对象与幻象引用关联,那么它就和没有任何引用关联任何时刻都可以被垃圾回收器回收

  • 原理:幻象引用必须使用引用队列(ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有幻象引用,就把这个幻象引用加入到与对象关联的引用队列中(这个是回收前入队的)

  • 使用场景:用来监控跟踪对象被垃圾回收器回收的活动,当一个幻象引用关联的对象被垃圾回收器回收之前会收到一条系统通知。例如:当前对象已经执行完析构函数 finalize() 了,还需要执行一些资源对象的关闭操作就通过该引用实现。

六、引用可达性

现阶段 GC 已经不再使用循环计数法,采用可达性分析算法来判断对象是否可以回收,那么就需要考虑对象的引用状态了,总的来说,会分为四种引用可达性:

  • 强可达(Strongly Reachable)

就是当一个对象可以有一个或多个线程可以不通过各种引用访问到的情况。比如,我们新创建一个对象,那么创建它的线程对它就是强可达。

  • 软可达(Softly Reachable)

就是当我们只能通过软引用才能访问到对象的状态。

  • 弱可达(Weakly Reachable)

类似前面提到的,就是无法通过强引用或者软引用访问,只能通过弱引用访问时的状态。这是十分临近fnalize状态的时机,当弱引用被清除的 时候,就符合 fnalize 触发的条件了

  • 幻象可达(Phantom Reachable)

上面流程图已经很直观了,就是没有强、软、弱引用关联,并且 fnalize 过了,只有幻象引用指向这个对象的时候

  • 不可达(unreachable)

当对象处于这种状态时,意味着对象可以清除了

七、后记

拓展文章:

© 著作权归作者所有
这个作品真棒,我要支持一下!
“限时免费“ 记录计算机最基础的知识,是我的复习笔记与学习笔记
0条评论
top Created with Sketch.