Java 幻象参照对象

Java 幻象参照对象,java,finalize,phantom-reference,Java,Finalize,Phantom Reference,幻影参考用于尸检操作。 Java规范规定,在清理幻影引用本身之前,幻影引用对象将不会被解除分配 我的问题是:这个特性(未释放的对象)有什么用途 (我提出的唯一想法是允许本机代码对对象进行事后清理,但这并不太令人信服)。编辑,因为我首先误解了这个问题: 引述如下: Java规范说 幻影参考在以下情况下不清除: 引用对象已排队,但 事实上,这是不可能的 用语言来说明这是否是正确的 完成与否。在一些实现中, JNI弱全局引用较弱 比幻影参考,并提供 可访问幻影的方法 对象 但是我没有发现其他的参考文献

幻影参考用于尸检操作。 Java规范规定,在清理幻影引用本身之前,幻影引用对象将不会被解除分配

我的问题是:这个特性(未释放的对象)有什么用途


(我提出的唯一想法是允许本机代码对对象进行事后清理,但这并不太令人信服)。

编辑,因为我首先误解了这个问题:

引述如下:

Java规范说 幻影参考在以下情况下不清除: 引用对象已排队,但 事实上,这是不可能的 用语言来说明这是否是正确的 完成与否。在一些实现中, JNI弱全局引用较弱 比幻影参考,并提供 可访问幻影的方法 对象


但是我没有发现其他的参考文献会这么说。

它可以让你们两个拥有幻影缓存,这在内存管理方面非常有效。 简单地说,如果您有创建成本很高但很少使用的大型对象,您可以使用幻影缓存来引用它们,并确保它们不会占用更有价值的内存。如果使用常规引用,则必须手动确保没有对对象的引用。您可以对任何对象进行相同的争论,但不必手动管理幻影缓存中的引用。只是要仔细检查他们是否被收集了


此外,您还可以使用一个框架(即工厂),其中引用作为虚拟引用提供。如果对象数量多且寿命短(即使用后处理),则此功能非常有用。如果你的程序员认为垃圾收集很神奇,那么清理内存非常方便。

我认为这个想法是让其他对象在原始对象的基础上做额外的清理。例如,如果无法扩展原始对象以实现某些最终化内容,则可以使用幻影引用

更大的问题是JVM不能保证对象会被最终确定,而且我假设扩展后也不能保证幻影引用在最终确定后完成它们的工作。

幻影引用可以用于执行垃圾收集前的操作,例如释放资源。相反,人们通常为此使用finalize()方法,这不是一个好主意。终结器会对垃圾收集器的性能产生可怕的影响,如果您不十分小心,可能会破坏应用程序的数据完整性,因为“终结器”是在随机线程中随机调用的。

在幻影引用的构造函数中,指定一个ReferenceQueue,一旦引用的对象变为“幻影可访问”,幻影引用将在该队列中排队。幻影可达性是指通过幻影引用以外的其他方式不可达。最初令人困惑的是,尽管phantom引用继续将被引用对象保存在私有字段中(与软引用或弱引用不同),但其getReference()方法始终返回null。这是因为您无法使对象再次强可访问。

您可以不时轮询ReferenceQueue,并检查是否存在任何新的PhantomReferences,这些PhantomReferences的引用对象已成为Phantoma可访问的对象。为了能够访问任何有用的内容,例如,可以从java.lang.ref.PhantomReference派生一个类,该类引用在垃圾收集之前应该释放的资源。只有当幻影引用本身变得不可访问时,才会对引用对象进行垃圾收集。

我能想到的防止释放的唯一好的用例是,某种JNI实现的异步数据源正在写入被引用的对象,并且必须被告知在内存被回收之前停止写入对象。如果允许先前的释放,一个简单的忘记处理()错误可能会导致内存损坏


这是过去使用finalize()的情况之一,可能导致了它的一些怪癖。

这是一个完美的解决方案,适用于没有生命周期管理机制的API,但您正在使用需要显式生命周期管理的东西来实现它

特别是任何一种API,它过去只使用内存中的对象,但您使用套接字连接或到其他更大备份存储的文件连接重新实现了它,它可以使用PhantomReference来“关闭”并在对象被GC之前清理连接信息,并且连接从未关闭,因为没有您可以使用的生命周期管理API接口

考虑将一个简单的地图移动到数据库中。放弃映射引用时,没有显式的“关闭”操作。然而,如果您已经实现了直写缓存,那么您希望能够完成任何写操作并关闭到“数据库”的套接字连接

下面是我用来做这类事情的一个类。请注意,对PhantomReferences的引用必须是非本地引用才能正常工作。否则,jit将导致它们在退出代码块之前提前排队

import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; /** * This class provides a way for tracking the loss of reference of one type of * object to allow a secondary reference to be used to perform some cleanup * activity. The most common use of this is with one object which might * contain or refer to another object that needs some cleanup performed * when the referer is no longer referenced. * * An example might be an object of type Holder, which refers to or uses a * Socket connection. When the reference is lost, the socket should be * closed. Thus, an instance might be created as in *
     *    ReferenceTracker trker = ReferenceTracker() {
     *        public void released( Socket s ) {
     *            try {
     *                s.close();
     *            } catch( Exception ex ) {
     *                log.log( Level.SEVERE, ex.toString(), ex );
     *            }
     *        }
     *  };
     *
*希望使用套接字连接并将其传递的软件
*在所有情况下,使用SocketHolder.get()引用套接字实例。
*然后,当删除所有SocketHolder引用时,套接字将
*通过所示的
released(java.net.Socket)
方法关闭 *上面。 * *{@link ReferenceTracker}类使用{@link PhantomReference}作为第一个参数 *包含对第二个参数的引用的映射的键。因此,当 *密钥实例已释放,密钥引用已排队,可以从 *队列,用于从映射中删除值,该值为t * interface Holder { * public T get(); * } * class SocketHolder implements Holder { * Socket s; * public SocketHolder( Socket sock ) { * s = sock; * } * public Socket get() { * return s; * } * } * * public SocketHolder connect( String host, int port ) throws IOException { * Socket s = new Socket( host, port ); * SocketHolder h = new SocketHolder( s ); * trker.trackReference( h, s ); * return h; * } *