- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我一直在阅读这篇关于 PhantomReference https://www.baeldung.com/java-phantom-reference 的文章以及在那里找到的简化示例代码:
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object object = new Object();
PhantomReference<Object> phantomReference = new PhantomReference<>(object, referenceQueue);
object = null;
System.gc();
Thread.sleep(1_000);
System.out.println("isEnqueued() after GC: " + phantomReference.isEnqueued());
Reference reference = referenceQueue.poll();
if(reference != null) {
System.out.println("isEnqueued() after poll(): " + phantomReference.isEnqueued());
}
}
这是输出:
isEnqueued() after GC: true
isEnqueued() after poll(): false
所以一切都按预期工作,对对象的强引用设置为 null,GC 检测到这一点,并将幻象引用添加到队列中。
现在在那篇文章中他们说:“垃圾收集器在执行其引用对象的 finalize 方法后向引用队列添加一个幻象引用。这意味着该实例仍在内存中。”
所以我想进行测试并重写 finalize 方法,例如:
Object object = new Object() {
@Override
protected void finalize() throws Throwable {
System.out.println("finalize()");
}
};
但随后输出不同,幻象引用不再添加到队列中:
finalize()
isEnqueued() after GC: false
有人能解释一下为什么在此更改后输出不同以及如何更改此代码以便将幻像引用添加到队列中吗?
我一直在 JDK 8 和 11 上对此进行测试,两个平台上的结果相同。
最佳答案
语句“垃圾收集器在执行其引用对象的终结方法后,将幻像引用添加到引用队列。”充其量有点草率。
你应该引用the specification :
If the garbage collector determines at a certain point in time that the referent of a phantom reference is phantom reachable, then at that time or at some later time it will enqueue the reference.
鉴于“幻影可达”的链接定义指出:
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 方法之后”对象是幻象可达的,因此将在该对象但不是立即之后入队。由于一个对象在其 finalize()
方法执行期间是强可达的,因此它至少需要一个额外的垃圾收集周期来检测它是否变为幻象可达。然后,“在那个时候或稍后的某个时间”,它会被排队。
如果你把程序改成
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object object = new Object() {
@Override
protected void finalize() throws Throwable {
System.out.println("finalize()");
}
};
PhantomReference<Object> phantomReference=new PhantomReference<>(object, referenceQueue);
object = null;
System.gc();
Thread.sleep(1_000);
System.gc();
Thread.sleep(1_000);
System.out.println("isEnqueued() after GC: " + phantomReference.isEnqueued());
Reference reference = referenceQueue.poll();
if(reference != null) {
System.out.println("isEnqueued() after poll(): " + phantomReference.isEnqueued());
}
您很可能会看到所需的输出,但必须强调的是,不能保证垃圾收集器在您调用 System.gc()
时会实际运行,或者它会在它运行的特定时间量,或者它将在特定周期内找到所有无法访问的对象。此外,入队在 gc 循环之后异步发生,因此即使在垃圾收集器完成并检测到特殊的可达性状态时,在引用入队之前可能还需要额外的时间。
请注意“It implies that the instance is still in the memory”这句话。也没有做对,但在这种情况下,它基于甚至在 Java 核心开发人员方面的误解。
创建 API 时,在规范中添加了一句话,您甚至可以在 Java 8 版本中找到:
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
这可能会导致对象仍然必须在内存中的天真假设,但是 The Java® Language Specification状态:
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable.
简单地说,如果程序的行为没有改变,对象的内存可能会提前回收。这尤其适用于应用程序根本无法使用该对象的场景,例如幻影引用。如果对象不再在内存中,程序的行为将不会改变,因此您不能假设它确实在内存中。
这引出了一个问题,为什么要将不清除幻象引用的规则添加到规范中。正如在 this answer 中讨论的那样,那个问题被提出来,根本无法回答。因此,此规则已在 Java 9 中删除,幻象引用在入队时被清除,如弱引用和软引用。这是不假设对象仍在内存中的更有力的理由,因为现在即使是非优化环境也可以在此时回收对象的内存。
关于Java PhantomReference 与 finalize(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53822132/
我正在使用 LWJGL 库,不幸的是,每当我的场景图中的节点需要死亡时,我需要自己释放纹理/vbo 缓冲区,我什至无法使用 finalize() 方法来做到这一点'不保证它将在 opengl 库期望的
你能帮我理解 PhantomReference 吗?我知道 PhantomReference 有助于跟踪对象何时从堆中移除,并且在调用 finalize 方法后可以访问。我试图用一些代码弄脏我的手,但
我试图了解 Java 中 PhantomReferences 的工作原理,并为此编写了这个程序。 public static void main(String[] args) throws Inter
来自javadoc : Unlike soft and weak references, phantom references are not automatically cleared by the
Java允许写: new PhantomReference(new Object(), null) 在这种情况下 new Object() 会被收集吗? 据我所知,虚引用是 finalize() 方法
我的问题总结了这一切: 强可达 Java PhantomReference 能否阻止其引用对象的内存被垃圾收集器 (GC) 回收? 详情如下: Callum posted this question也
考虑一个使用 PhantomReferences 来避免终结器的库,同时确保释放一些 JNI 资源。 一种架构涉及引用队列和阻塞在引用队列上执行清理操作的线程。 现在的问题是:如何对这一切进行测试?
假设我创建了一个实现 Closable 的类 MyClass。因此,在 close() 方法中,我将释放一些非常重要的资源。好吧,因为它是非常重要的资源,所以我创建了某种安全网络(如《Effectiv
据我所知,当引用指向的对象被删除时,引用会落入 QueueReference。 这里是一个例子,我正要演示这个,但它不起作用。 if 中的代码从未执行过。这是什么意思。我用错了吗?或者 Garbage
演示代码: import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; public class Main
关于 PhantomReference 我唯一知道的是, 如果您使用它的 get() 方法,它将始终返回 null 而不是对象。有什么用? 通过使用 PhantomReference,您可以确保对象无
它们都可以用于清理,几乎没有保证,但是 PR 需要更多的线束编码。那么,有两个选择,为什么我必须更喜欢一个而不是另一个? Javadoc 9 describes finalize问题很大,但这并不会自
我一直在阅读这篇关于 PhantomReference https://www.baeldung.com/java-phantom-reference 的文章以及在那里找到的简化示例代码: publi
关于PhantomReference,我唯一知道的是, 如果你使用它的 get() 方法,它总是返回 null 而不是对象。有什么用? 通过使用 PhantomReference,您可以确保对象无法通
Soft 的文档-,Weak - 和PhantomReference都包含类似于以下内容的行(取自 PhantomReference): At that time it will atomically
我有一个共享资源,我想知道有多少其他对象仍在使用该资源。为此,我想使用 PhantomReference。 由于 ReferenceQueue 不跟踪为它们注册的引用(source,“通知”部分),我
这是我的代码 public class FinalizableObject { @Override protected void finalize() throws Throwable
我有一个 PR,一个 PR 指向的对象 O,以及一个为 PR 设置的 RQ。我有一个不断轮询 RQ 的线程,当它在 RQ 中找到第一个引用时,该线程打印它找到它的时间,然后退出。 一切正常,但是当 O
Javadoc 8 PhantomReference 状态: Phantom references are most often used for scheduling pre-mortem clea
正如 Hans Boehm 在 Google I/O '17 演讲“How to Manage Native C++ Memory in Android”中建议我使用 PhantomReference
我是一名优秀的程序员,十分优秀!