幻像参考的实际用途是什么 - JAVA?

时间:2015-11-02 11:39:10

标签: java

搜索了很多关于幻影参考的内容,但无法找到它的实际用法。从逻辑上讲,get()方法在Phantom References

的情况下返回null

1 个答案:

答案 0 :(得分:8)

您可以按照blog

进行操作
  

PhantomReferences有什么用?我只知道两个严重的情况   对于他们:首先,他们允许您确定一个对象的确切时间   被从记忆中删除。事实上,它们是唯一确定的方法   那。这通常没那么有用,但可能会派上用场   某些特定情况,如操纵大图像:如果   你肯定知道图像应该是垃圾收集的,你可以   在尝试加载下一张图片之前,请等到它   因此不太可能使可怕的OutOfMemoryError。

     

其次,PhantomReferences避免了一个基本问题   finalization:finalize()方法可以通过创建“复活”对象   新的强烈参考。那么,你说什么?嗯,问题是   现在必须确定覆盖finalize()的对象   垃圾在至少两个单独的垃圾收集周期中才能实现   被收集。当第一个循环确定它是垃圾时,它   有资格完成定稿。因为(苗条,但是   不幸的是真实的)物体被“复活”的可能性   在最终确定期间,垃圾收集器必须在之前再次运行   实际上可以删除对象。因为最终确定可能不会   及时发生了,任意数量的垃圾   在对象等待时可能发生了收集周期   定稿。这可能意味着实际清理工作严重延误   垃圾对象,这就是为什么你甚至可以获得OutOfMemoryErrors   大部分堆都是垃圾。

另请阅读:The Mysterious Phantom Reference

  

请考虑以下代码。

public class Foo {

    private String bar;

    public Foo(String bar) {
        this.bar = bar;
    }

    public String foo() {
        return bar;
    }
}
     

因此,在对象被完全取消引用后,让我们说   应用程序我想要一些如何调用foo()。这是我的一些代码   预计可以通过一个小问题来完成这项工作。

// initialize
ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>();
ArrayList< PhantomReference<Foo>> list=new ArrayList<PhantomReference<Foo>>();

for ( int i = 0; i < 10; i++) {
    Foo o = new Foo( Integer.toOctalString( i));
    list.add(new PhantomReference<Foo>(o, queue));
}

// make sure the garbage collector does it’s magic
System.gc();

// lets see what we’ve got
Reference<? extends Foo> referenceFromQueue;
for ( PhantomReference<Foo> reference : list)
    System.out.println(reference.isEnqueued());

while ( (referenceFromQueue = queue.poll()) != null) {
    System.out.println(referenceFromQueue.get());
    referenceFromQueue.clear();
}
     

PhantomReference采用Foo和ReferenceQueue的实例。以来   没有句柄留给Foo,它应该立即死亡。接下来,告诉   要收集的VM,因为它没有足够的堆来触发a   收藏自然。我要问的第一件事就是   PhantomReference是;你被列入了吗?在这种情况下的答案   将是真的。接下来我要求队列参考,但你可以   看,调用get()总是返回null。关于唯一的解决方案   有意义的是包装你想要交互的资源或对象   在PhantomReference的子类中。

public class FinalizeStuff<Foo> extends PhantomReference<Foo> {

    public FinalizeStuff(Foo foo, ReferenceQueue<? super Foo> queue) {
        super(foo, queue);
    }

    public void bar() {
        System.out.println("foobar is finalizing resources");
    }
}
     

在这种情况下,我不打算将Foo包装在子类中   似乎违反了PhantomReference的精神。相反,我要去   包装与Foo相关的资源并与之交互。现在我能   这样做。

// initialize
ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>();
ArrayList< FinalizeStuff<Foo>> list = new ArrayList<FinalizeStuff<Foo>>();
ArrayList<Foo> foobar = new ArrayList<Foo>();

for ( int i = 0; i < 10; i++) {
    Foo o = new Foo( Integer.toOctalString( i));
    foobar.add(o);
    list.add(new FinalizeStuff<Foo>(o, queue));
}

// release all references to Foo and make sure the garbage collector does it’s magic
foobar = null;
System.gc();

// should be enqueued
Reference<? extends Foo> referenceFromQueue;
for ( PhantomReference<Foo> reference : list) {
    System.out.println(reference.isEnqueued());
}

// now we can call bar to do what ever it is we need done
while ( (referenceFromQueue = queue.poll()) != null) {
    ((FinalizeStuff)referenceFromQueue).bar();
    referenceFromQueue.clear();
}