Java - Reference 小记

354 阅读2分钟

偶然接触到 MemoryCache ,其中使用了 ReferenceQueue 作为失效缓存监听,不明里面对 Reference 的处理逻辑,遂稍作梳理。

Reference 类型

Java 中定义了四种引用对象类型,分别为

  • StrongReference:强引用,GC时不会被回收
  • SoftReference:软引用,内存足够时,GC不会回收;内存不足时,GC会将其回收
  • WeakReference:弱引用,GC会回收
  • PhantomReference:幽灵引用,待深入

Reference 状态

image-20200609170019303

  • Active 活跃:对象创建后的初始状态
  • Pending 待定:当 queue 不为空且GC判定对象可达性发生变化
  • Enqueued 待回收:由内部线程转化
  • Inactive 非活跃:当 queue 为空且GC判定对象可达性发送变化

几个特殊的常量:

  • ReferenceQueue.NULL:表示无指定queue
  • ReferenceQueue.ENQUEUED:表示当前节点已入queue,当前queue被指定该值

通信媒介 - ReferenceQueue

在创建 Reference 时可关联指定 ReferenceQueue,然后可在与 Reference 关联的 ReferenceQueue 中获取到即将被回收的 Reference 对象,用于后续相关操作,如删除对应的缓存数据。

所以 ReferenceQueue 是 JVM GC 与 代码层的通信介质,用于监听对象引用的可达性变化。

内部线程 - ReferenceHandler

ReferenceHandler 负责维护各引用的状态。

本质上是个 Thread

/* High-priority thread to enqueue pending References
     */
    private static class ReferenceHandler extends Thread {

        private static void ensureClassInitialized(Class<?> clazz) {
            try {
                Class.forName(clazz.getName(), true, clazz.getClassLoader());
            } catch (ClassNotFoundException e) {
                throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
            }
        }

        static {
            // pre-load and initialize InterruptedException and Cleaner classes
            // so that we don't get into trouble later in the run loop if there's
            // memory shortage while loading/initializing them lazily.
            ensureClassInitialized(InterruptedException.class);
            ensureClassInitialized(Cleaner.class);
        }

        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }

        public void run() {
            while (true) {
              	// 循环将 pending 引用移入 queue 中
                tryHandlePending(true);
            }
        }
    }

Summary

All in all,梳理一遍Reference内部处理逻辑。

image-20200609164038531

Stay Foolish

  • Reference 处于 Active 时,第一个 pending 是怎么设置上去的?
  • 为何幽灵引用? PhantomReference 是如何产生的?

参考