为什么幻影参考没有排队?

时间:2018-02-23 09:33:37

标签: java phantom-reference

我倾向于幻影引用,我很困惑当引用物被垃圾收集时,幻像引用是如何排队的。

这是我的代码

    Object s = new Object();

    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    PhantomReference<Object> ref = new PhantomReference<Object>(s, queue);

    s = null;
    System.gc();
    TimeUnit.SECONDS.sleep(1);
    System.out.println(queue.poll());

正如预期的那样,queue.poll将返回幻像引用:ref。

但是如果我对代码做了一点改动:删除局部变量“ref”,queue.poll将返回null。

所以我可以推断,当JVM尝试垃圾收集一个对象时,它会检查所有引用以查看是否有任何可以到达该对象的引用。

这应该是一个非常缓慢的进展。?

我设计了一个程序:使用幻像引用来跟踪资源泄漏。分配资源时,幻像引用是新的并绑定到资源。然后我发现:必须存储所有幻像引用,否则幻像引用不会入队。

我检查了网络代码,发现netty存储了所有幻像引用:io.netty.util.ResourceLeakDetector #allallaks。

2 个答案:

答案 0 :(得分:1)

垃圾收集器像任何其他对象一样处理引用对象。来自the documentation

  

如果注册的引用本身无法访问,则它永远不会被排队。

理论上,是的,使用引用对象会导致垃圾收集效率低下,因此我不会为每个应用程序对象创建引用对象。但在实践中,参考对象集往往非常小:它们旨在跟踪资源,如数据库连接,而不是任意对象。

答案 1 :(得分:1)

the specification所述,“如果注册的引用本身无法访问,则它将永远不会入队”。但是,这不应该让人感到意外,因为没有定义特殊可达性状态的可达参考对象,就没有特殊的可达性状态。规范明确指出的一点是,只要引用对象尚未入队,就没有从队列到引用对象的引用。

  

所以我可以推断,当JVM尝试垃圾收集一个对象时,它会检查所有引用以查看是否有任何可以到达该对象的引用。

除了JVM从不尝试收集单个对象之外,您刚刚描述了垃圾收集的全部内容,遍历所有引用以找出哪些对象仍然可以访问。

  

这应该是一个非常缓慢的进展。?

如果垃圾收集器为每个对象再次执行此操作,那将非常慢。但是垃圾收集器会对所有对象进行遍历。遍历期间未遇到的对象本身就是垃圾,因此这些无法访问的对象不需要任何特殊处理,包括放弃的引用对象。

但是,垃圾收集当然会带来开销,这就是为什么System.gc()不应该被调用的原因,除非在示例程序中进行调试。