Guava Cache实现原理——引用类型回收
系列文章:
Guava Cache实现原理——开篇&基本实现
Guava Cache实现原理——LRU回收实现
Guava Cache实现原理——引用类型回收
Guava Cache实现原理——高效回收技巧
目录
一、前言
上一篇文章我们已经介绍了Guava Cache的LRU算法的实现,本篇文章我们继续分析Guava Cache是如何对引用类型进行回收的。
二、实现
1、引用类型的基本使用
我们首先回顾下在Guava Cache中如何使用引用类型。在初始化Guava Cache的时候,我们通过weakkeys、weakValues或者softValues来设置对应的Key和Value为软引用或者弱引用。这样GC回收或者内存吃紧的时候就能够利用GC对相应的key或者value进行回收(前提是没有其他强引用)。
思考:为什么没有softKeys()
2、引用类型的实现
熟悉Java引用类型使用的同学应该都能够想到如何实现了。就是根据具体的引用类型将value或者key封装成对应的Reference类。在Guava Cache中提供了如下三个类来实现对应的强引用、软引用和弱引用对象。
以下是弱引用的实现类。具体实现很简单就是继承实现Java的SoftReference类即可,其他类型类同,这里不再做具体介绍,具体请自行查看源码。
使用过引用类型的同学都知道,在构建引用类型的时候需要传递一个Queue队列,当引用类型被回收后就会被JVM放到这个Queue中。在Guava Cache中,在构建每个Segment的时候就会构建出对应的Queue(如下图)。后面在当前Segment中创建引用类型的时候就使用这个对应的Queue。
如下是软引用类型构建的时候的实现,即使用Segment的Queue直接构建出软引用对象,其他类同这里不再做详细介绍,自行查看源码。
3、引用类型的回收
上一节已经介绍过了,当引用类型(非强引用)被回收后,其对应的引用类型对象会被放到其初始化的队列中。于是我们只要通过不断从Queue中读取数据就知道哪些key或者value被回收了。
在Guava Cache中,引用类型的回收和之前的LRU回收一样,有两个地方会触发,其分别是:
-
在get的时候,如果tryLock获取到锁了,则进行回收。
-
在modify的时候(put|add|delete),此时肯定获取到了锁,直接进行回收。
具体回收都是调用drainReferenceQueues方法,如下:
如下则是对value的引用对象的时候过程,和普通的引用对象的处理类似。首先从Queue中获取到哪些引用类型的对象被回收了,然后在从map中将对应的引用类型进行移除操作。
如下是key的引用对象的回收过程代码:
4、总结
-
其实引用类型的回收很简单,就是利用了Reference的特性。
当其引用的对象被回收后,就会将引用对象放到对应的Queue中。
我们只需不断从Queue中获取出引用对象,然后将其从map中移除即可。
-
和LRU回收一样,在get的时候,如果获取到锁才执行回收。
在modify操作中则直接回收。
三、惯例
如果你对本文有任何疑问或者高见,欢迎添加公众号共同交流探讨(添加公众号可以获得”Java高级架构“上10G的视频和图文资料哦)。