GC回收之引用(强引用、软引用、弱引用、虚引用)

小熙前些天看到关于GC回收的一张流程图,查阅之后分享下。

一、概述:

1. 文字叙述:

Java中引用数据类型的引用大致分为四种(JDK 1.2开始),由高到低分别是:强引用、软引用、弱引用、虚引用 (幻想引用)

2. 图释:(这四种引用主要的区别体现在,对象在不同的可达性状态下对垃圾收集的影响)
引用类别

二、详解:

1. 强引用(strong reference):

(1) 强引用是我们最常见,也是最熟悉的普通对象引用,如创建一个对象引用他(new 对象)。只要处于此种引用,该对象就表示永远不会处于不可及状态,GC就不会回收他,即使JVM内存空间不足,JVM宁愿抛OutOfMemoryError运行时错误(OOM),让程序异常终止,也不会靠回收强引用对象来解决内存不足的问题。

(2)对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为null,就意味着此对象可以被垃圾收集了。但要注意的是,并不是赋值为null后就立马被垃圾回收,具体的回收时机还是要看垃圾收集策略的。

示例,在不用对象的时候将引用赋值为 null(ArrayList 的 clear() 方法实现):

 public void clear() {
     modCount++;

     // clear to let GC do its work
     for (int i = 0; i < size; i++)
         elementData[i] = null;
     size = 0;
 }

2. 软引用(soft reference):

(1)软引用在内存足够的时候,GC不会回收它。 只有当JVM认定内存空间不足时才会去回收软引用指向的对象。软引用通常可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,java虚拟机就会把这个软引用加入到与之关联的引用队列中(详见下面的示例)。

(2)JVM会确保在抛出内存溢出(OOM)前清理软引用指向的对象,他会尽可能优先回收长时间闲置不用的软引用指向的对象,对那些刚构建的或刚使用过的软引用指向的对象尽可能的保留。基于软引用的这些特性,软引用可以用来实现很多内存敏感点的缓存场景(如图片缓存和网页缓存),即如果内存还有空闲,可以暂时缓存一些业务场景所需的数据,当内存不足时就可以清理掉,等后面再需要时,可以重新获取并再次缓存。这样就确保在使用缓存提升性能的同时,不会导致耗尽内存。

示例:

    // 软应用
    // new User 对象,user 是强引用
    User user = new User();
    // 将 user 强引用转换为 userSoftReference 软引用
    SoftReference<User> userSoftReference = new SoftReference<>(user);
    // 获取软引用对象,如果被 GC 回收则返回 null
    User userSoft = userSoftReference.get();

    // 当通过软引用获取的对象为 null 的时候,辅助强应用为 null 可以调用 GC 回收引用
    if(userSoft == null) {
      user = null;
      System.gc();
    }

    // 是否被 GC 回收,加入到关联队列中
    boolean enqueued = userSoftReference.isEnqueued();

3. 弱引用(weak reference):

(1)GC在扫描它所管辖的内存区域时,只要发现弱引用的对象,不管内存空间是否有空闲,都会立刻回收它。 是一种十分临近finalize状态的情况,当弱引用被清除的时候,就符合finalize的条件了。弱引用与软引用最大的区别就是弱引用比软引用的生命周期更短暂。

(2)具体的回收时机还是要看垃圾回收策略的,并且垃圾回收器是一个优先级很低的线程,因此那些弱引用的对象并不是说只要达到弱引用状态就会立马被回收。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中

示例:

    // 弱引用
    // new User 对象,user 是强引用
    User user = new User();
    // 将 user 强引用转换为 userWeakReference 软引用
    WeakReference<User> userWeakReference = new WeakReference<>(user);
    // 获取弱引用对象,如果被 GC 回收则返回 null
    User userWeak = userWeakReference.get();

    // 返回是否被 GC 标记为即将回收的垃圾,是否在关联的队列中
    boolean enqueued = userWeakReference.isEnqueued();

4. 虚引用(phantom reference):

(1)虚引用在任何时候都可能被GC回收,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,并且虚引用并不会决定对象的生命周期。

(2)虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用,也有人利用虚引用监控对象的创建和销毁。幻象引用的get方法永远返回null,主要用于检查对象是否已经从内测中删除。

示例:

    // 虚引用 
    // new User 对象,user 是强引用
    User user = new User();
    // 创建必要的关联队列进行存贮,虚引用随时会会被 GC 回收
    ReferenceQueue<User> userReferenceQueue = new ReferenceQueue<>();
    // 将 user 强引用转换为 userPhantomReference 虚引用
    PhantomReference<User> userPhantomReference = new PhantomReference<>(user, userReferenceQueue);
    // 任何时候调用都是null
    User getUserPhantomReference = userPhantomReference.get();
    // 判断是否被内存删除
    boolean enqueued = userPhantomReference.isEnqueued();

三、总结:

  1. 见表格:
引用类型GC回收时间用处存活时间
强引用从来不会被回收一般对象的引用JVM停止运行时
软引用在内存不足时对象缓存内存不足时
弱引用在垃圾回收时对象缓存GC回收后
虚引用任何时间监控对象的创建和销毁Unknow
  1. 在程序设计中弱引用与虚引用一般很少使用,软引用使用的几率比较大,因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值