gpt4 book ai didi

java - 为什么 PhantomReference 的入队比 WeakReference 或 SoftReference 需要更多的 GC 周期?

转载 作者:行者123 更新时间:2023-11-30 07:41:00 25 4
gpt4 key购买 nike

我决定继续https://stackoverflow.com/a/41998907/2674303在单独的主题中。

让我们考虑以下示例:

public class SimpleGCExample {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<Object> queue=new ReferenceQueue<>();
SimpleGCExample e = new SimpleGCExample();
Reference<Object> pRef=new PhantomReference<>(e, queue),
wRef=new WeakReference<>(e, queue);
e = null;
for(int count=0, collected=0; collected<2; ) {
Reference ref=queue.remove(100);
if(ref==null) {
System.gc();
count++;
}
else {
collected++;
System.out.println((ref==wRef? "weak": "phantom")
+" reference enqueued after "+count+" gc polls");
}
}
}

@Override
protected void finalize() throws Throwable {
System.out.println("finalizing the object in "+Thread.currentThread());
Thread.sleep(100);
System.out.println("done finalizing.");
}
}

Java 11 打印如下:

finalizing the object in Thread[Finalizer,8,system]
weak reference enqueued after 1 gc polls
done finalizing.
phantom reference enqueued after 3 gc polls

前两行可以改变顺序。看起来它们是并行工作的。

最后一行有时打印 2 个 gc polls,有时打印 3 个

所以我看到 PhantomReference 的入队需要更多的 GC 周期。怎么解释呢?它是否在文档中的某处提到过(我找不到)?

附言

弱引用java文档:

Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. At the same time it will declare all of the formerly weakly-reachable objects to be finalizable. At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues

PhantomReference java 文档:

Suppose the garbage collector determines at a certain point in time that an object is phantom reachable. At that time it will atomically clear all phantom references to that object and all phantom references to any other phantom-reachable objects from which that object is reachable. At the same time or at some later time it will enqueue those newly-cleared phantom references that are registered with reference queues

我不清楚区别

P.S.(我们正在谈论具有非平凡 finalize 方法的对象)

@Holger 回答了我的问题:

他(没有性别歧视,但我想是)向我指出了 java doc并注意到 PhantomReference 与 Soft 和 Weak References 相比包含额外的短语:

An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.
An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it

我的下一个问题是关于它已完成是什么意思我预计这意味着完成方法已完成

为了证明这一点,我像这样修改了应用程序:

public class SimpleGCExample {
static SimpleGCExample object;

public static void main(String[] args) throws InterruptedException {
ReferenceQueue<Object> queue = new ReferenceQueue<>();
SimpleGCExample e = new SimpleGCExample();
Reference<Object> pRef = new PhantomReference<>(e, queue),
wRef = new WeakReference<>(e, queue);
e = null;
for (int count = 0, collected = 0; collected < 2; ) {
Reference ref = queue.remove(100);
if (ref == null) {
System.gc();
count++;
} else {
collected++;
System.out.println((ref == wRef ? "weak" : "phantom")
+ " reference enqueued after " + count + " gc polls");
}
}
}

@Override
protected void finalize() throws Throwable {
System.out.println("finalizing the object in " + Thread.currentThread());
Thread.sleep(10000);
System.out.println("done finalizing.");
object = this;
}
}

我看到以下输出:

weak reference enqueued after 1 gc polls
finalizing the object in Thread[Finalizer,8,system]
done finalizing.

然后应用程序挂起。我认为这是因为对于弱/软引用,GC 以下列方式工作:一旦 GC 检测到该对象是弱/软可访问的,它就会并行执行 2 个操作:

  • 将 Weak/Soft 加入已注册的 ReferenceQueue 实例中
  • 运行终结方法

因此对于添加到 ReferenceQueue 中,对象是否被复活并不重要。

但是对于 PhantomReference 操作是不同的。一旦 GC 检测到该对象是 Phantom Reachable,它就会按顺序执行以下操作:

  • 运行终结方法
  • 检查对象仍然只是 phantomReachable(检查对象在 finalize 方法执行期间没有复活)。并且只有当对象是 GC 时,才会将幻象引用添加到 ReferenceQueue

但是@Holger 说它已经完成 意味着 JVM 启动了 finalize() 方法调用并且为了将 PhantomReference 添加到 ReferenceQueue 中它是否完成都没有关系不是。但看起来我的例子表明它真的很重要。

坦率地说,我不明白为弱引用和软引用添加到 ReferenceQueue 中的区别。想法是什么?

最佳答案

关键是the package documentation中“幻象可达”的定义:

  • An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.

大胆强调我的

请注意,当我们删除 finalize() 方法时,会立即收集虚引用以及弱引用。

这是 JLS §12.6 的结果:

For efficiency, an implementation may keep track of classes that do not override the finalize method of class Object, or override it in a trivial way.

We encourage implementations to treat such objects as having a finalizer that is not overridden, and to finalize them more efficiently, as described in §12.6.1.

不幸的是,§12.6.1 没有讨论“拥有一个未被覆盖的终结器”的后果,但很容易看出,该实现只是将这些对象视为已经终结,从不将它们排队等待终结,并且因此,能够立即回收它们,这会影响典型 Java 应用程序中的大多数对象。

另一种观点是,确保 finalize() 方法最终被调用的必要步骤,即 Finalizer 实例的创建和链接,将对于具有平凡终结器的对象,可以省略。此外,在逃逸分析后消除纯本地对象的创建,仅适用于这些对象。

由于没有终结器的对象的弱引用和幻像引用之间没有行为差异,我们可以说终结器的存在及其复活对象的可能性是幻影引用存在的唯一原因,是仅当可以安全地假设对象无法再复活时,才能够执行对象的清理¹。

¹ 然而,在 Java 9 之前,这种安全性并不是万无一失的,因为幻象引用不会被自动清除,而且深度反射允许扭曲整个概念。

关于java - 为什么 PhantomReference 的入队比 WeakReference 或 SoftReference 需要更多的 GC 周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56705169/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com