Phantom References in Java – Java中的幻影引用

最后修改: 2018年 1月 10日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll have a look at the concept of a Phantom Reference – in the Java language.

在这篇文章中,我们将看看Java语言中的 “幻影引用 “概念。

2. Phantom References

2.幻影参考资料

Phantom references have two major differences from soft and weak references.

幻影引用与softweak引用有两个主要区别。

We can’t get a referent of a phantom reference. The referent is never accessible directly through the API and this is why we need a reference queue to work with this type of references.

我们无法获得一个幻影引用的引用。引用永远无法通过API直接访问,这就是为什么我们需要一个引用队列来处理这种类型的引用。

The Garbage Collector adds a phantom reference to a reference queue after the finalize method of its referent is executed. It implies that the instance is still in the memory.

垃圾收集器将一个幻象引用添加到引用队列中在其引用的finalize方法被执行后。这意味着该实例仍在内存中。

3. Use Cases

3.使用案例

There’re two common use-cases they are used for.

有两种常见的使用情况,它们被用于。

The first technique is to determine when an object was removed from the memory which helps to schedule memory-sensitive tasks. For example, we can wait for a large object to be removed before loading another one.

第一种技术是确定一个对象何时从内存中移除,这有助于安排对内存敏感的任务。例如,我们可以等待一个大对象被移除后再加载另一个对象。

The second practice is to avoid using the finalize method and improve the finalization process.

第二个做法是避免使用finalize方法,改进finalization过程

3.1. Example

3.1.例子

Now, let’s implement the second use case to practically figure out how this kind of references works.

现在,让我们来实现第二个用例,实际弄清楚这种引用是如何工作的。

First off, we need a subclass of the PhantomReference class to define a method for clearing resources:

首先,我们需要一个PhantomReference类的子类来定义一个清除资源的方法。

public class LargeObjectFinalizer extends PhantomReference<Object> {

    public LargeObjectFinalizer(
      Object referent, ReferenceQueue<? super Object> q) {
        super(referent, q);
    }

    public void finalizeResources() {
        // free resources
        System.out.println("clearing ...");
    }
}

Now we’re going to write an enhanced fine-grained finalization:

现在我们要写一个增强的细粒度的最终处理。

ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
List<LargeObjectFinalizer> references = new ArrayList<>();
List<Object> largeObjects = new ArrayList<>();

for (int i = 0; i < 10; ++i) {
    Object largeObject = new Object();
    largeObjects.add(largeObject);
    references.add(new LargeObjectFinalizer(largeObject, referenceQueue));
}

largeObjects = null;
System.gc();

Reference<?> referenceFromQueue;
for (PhantomReference<Object> reference : references) {
    System.out.println(reference.isEnqueued());
}

while ((referenceFromQueue = referenceQueue.poll()) != null) {
    ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();
    referenceFromQueue.clear();
}

First, we’re initializing all necessary objects: referenceQueue – to keep track of enqueued references, references – to perform cleaning work afterward, largeObjects – to imitate a large data structure.

首先,我们要初始化所有必要的对象。referenceQueue – 用于跟踪排队的引用,references – 用于事后执行清理工作,largeObjects – 用于模仿大型数据结构。

Next, we’re creating these objects using the Object and LargeObjectFinalizer classes.

接下来,我们使用ObjectLargeObjectFinalizer类创建这些对象。

Before we call the Garbage Collector, we manually free up a large piece of data by dereferencing the largeObjects list. Note that we used a shortcut for the Runtime.getRuntime().gc() statement to invoke the Garbage Collector.

在我们调用垃圾收集器之前,我们通过取消引用largeObjects列表来手动释放一个大数据。注意,我们使用了Runtime.getRuntime().gc()语句的快捷方式来调用垃圾收集器。

It’s important to know that System.gc() isn’t triggering garbage collection immediately – it’s simply a hint for JVM to trigger the process.

要知道,System.gc()并没有立即触发垃圾收集,它只是提示JVM触发该过程。

The for loop demonstrates how to make sure that all references are enqueued – it will print out true for each reference.

for循环演示了如何确保所有引用都被排队 – 它将为每个引用打印出true

Finally, we used a while loop to poll out the enqueued references and do cleaning work for each of them.

最后,我们用一个while循环来轮询排队的引用,并为每个引用做清洁工作。

4. Conclusion

4.结论

In this quick tutorial, we introduced Java’s phantom references.

在这个快速教程中,我们介绍了Java的幻象引用。

We learned what these are and how they can be useful in some simple and to-the-point examples.

我们了解了这些是什么,以及它们如何在一些简单和切题的例子中发挥作用。