Mybatis系列6:弱引用缓存,软引用缓存和虚引用缓存

弱引用缓存,软引用缓存和虚引用缓存,说实话,要不是看Mybatis的源码,我还真不知道,既然有了,我们就分析一下吧。
前面在研究ThreadLocal时,我们分析了弱引用的典型用法,除此之外就再无见过,而软引用和虚引用更是不知道有何用。所以今天我们就一起研究一下。

1. 强应用,弱引用,软引用和虚引用

强引用
强引用是 Java 编程中最普遍的引用,例如 Object o均 = new Object()中,新建的 Object对象就是被强引用的。如果一个对象被强引用,即使是 Java 虚拟机内存空间不足时,GC 也绝不会回收该对象。当 Java 虚拟机内存不足时,就可能会导致内存溢出,我们常见的就是 OutOfMemoryError 异常 。
软引用
软引用是引用强度仅弱于强引用的一种引用,它使用类 SoftReference 来表示。当 Java虚拟机内存不足时, GC 会回收那些只被软引用指向的对象,从而避免内存溢出。在GC 释放了那些只被软引用指向的对象之后,虚拟机内存依然不足,才会抛出OutOtMemoryError 异常。软引用适合引用那些可以通过其他方式恢复的对象,例如数据库缓存中的对象就可以从数据库中恢复,所以软引用可以用来实现缓存。
另外,由于在程序使用软引用之前的某个时刻 ,其所指向的对象可能己经被 GC 回收掉了,所以通过 Reference.get()方法来获取软引用所指向的对象时,总是要通过检查该方法返回值是否为 null ,来判断被软引用的对象是否还存活。
引用队列( ReferenceQueue )
在很多场景下,我们的程序需要在一个对象的可达性(是否已经被 GC 回收)发生变化时得到通知,引用队列就是用于收集这些信息的队列。在创建 So负Reference 对象时,可以为其关联一个引用队列,当 So企Reference 所引用的对象被 GC 回收时, Java 虚拟机就会将该 SoftReference 对象添加到与之关联的引用队列中。当需要检测这些通知信息时,就可以从引用队列中获取这些 SoftReference 对象。不仅是 So丘Reference,下面介绍的弱引用和幽灵引用都可以关联相应的队列。可以参考java.util.WeakHashMap 的代码,其中应用了弱引用和引用队列的相关知识。
弱引用
弱引用的强度比软引用的强度还要弱。弱引用使用 WeakReference 来表示,它可以引用一个对象,但并不阻止被引用的对象被 GC 回收。在 NM 虚拟机进行垃圾回收时,如果指向一个对象的所有引用都是弱引用,那么该对象会被回收。由此可见,只被弱引用所指向的对象的生存周期是两次 GC 之间的这段时间,而只被软引用所指向的对象可以经历多次 GC,直到出现内存紧张的情况才被回收。
弱引用典型的应用情景是就是 JDK 提供的 java.util.WeakHashMap 。WeakHashMap.Entry实现继承了 WeakReference, Enty弱引用 key,强引用 value.
在这里插入图片描述
当不再由强引用指向 key 时,则 key 可以被垃圾回收,当 key 被垃圾回收之后, 对应的 Entry 对象会被 Java 虚拟机加入到其 关联的队列中。当应用程序下次操作WeakHashMap 时,例如对 WeakHashMap 的扩容操作,就会遍历关联的引用队列,将其中的 Entry 对象从 WeakHashMap 中删除 。
幽灵引用
在介绍幽灵引用之前,要先了解一下 Java 提供的对象终止化机制。在 Object 类里面有个 finalize()方法,设计该方法的初衷是在一个对象被真正回收之前,执行一些清理工作,但由于 GC 的运行时间是不固定的,所以这些清理工作的实际运行时间也是无法预知的,而且 JVM 虚拟机不能保证 finalize()方法一定会被调用 。每个对象的 finalize()方法至多由 GC 执行一次,对于再生对象 GC 不会再次调用其 finalize()方法 。 另外,使用 finalize()方法还会导致严重的内存消耗和性能损失。由于 finalize()方法存在的种种问题,该方法现在已经被废弃,而我们可以使用幽灵引用实现其替代方案。
幽灵引用,又叫“虚引用”,它是最弱的一种引用类型,由类 PhantomReference 表示。在引用的对象未被 GC 回收时,调用前面介绍的 SoftReference 以及 WeakReference 的get()方法,得到的是其引用的对象: 当 引用的对象已经被 GC 回收时,则得到 null。但是 PhantomReference.get()方法始终返回 null 。
在创建幽灵引用的时候必须要指定一个引用队列。当 GC 准备回收一个对象时,如果发现它还有幽灵引用,就会在回收对象的内存之前,把该虚引用加入到与之关联的引用队列中 。程序可以通过检查该引用队列里面的内容,跟踪对象是否己经被回收并进行一些清理工作。

这种引用到底有啥用呢?就是了回收的时候能够收到一个系统通知。

2. SoftCache和WeakCache的实现

介绍完 Java 提供的四种引用类型,我们来介绍 SoftCache 的实现 。
其节点的定义为:

  private static class SoftEntry extends SoftReference<Object> {
    private final Object key;

    SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
      super(value, garbageCollectionQueue);
      this.key = key;
    }
  }

这里的key是强引用,value是一个ReferenceQueue类型的队列。再看putf()方法:

  public void putObject(Object key, Object value) {
    removeGarbageCollectedItems();
    delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));
  }

这里的key是强引用,value变成了软引用,这里的put()方法除了向缓存中添加缓存项,还会清除己经被 GC 回收的缓存项。getObject ()方法除了从缓存中查找对应 的 value,处理被GC回收的value对应的缓存项 , 还会更新 hardLinksToAvoidGarbageCollection 集合。后面这个根据名字来推断就是设置硬连接防止被回收。其代码不必再放了。
WeakCache 的实现与 SoftCache 基本类似,唯一的区别在于其中使用 WeakEnty(继承自WeakReference)封装真正的 value 对象,其他实现完全一样。

SoftCache和WeakCache的应用
这两种明显与其他的不一样,那有啥用呢?全网没有找到,以后再说吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵横千里,捭阖四方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值