我唯一了解的PhantomReference
是
- 如果使用其
get()
方法,它将始终返回null
而不是对象。它有什么用? - 通过使用
PhantomReference
,可以确保不能从finalize
方法中复现该对象。
但是这个概念/类的用途是什么?
您是否曾在您的任何项目中使用过此功能,或者您有任何应使用此功能的示例?
我唯一了解的PhantomReference
是
get()
方法,它将始终返回null
而不是对象。它有什么用?PhantomReference
,可以确保不能从finalize
方法中复现该对象。但是这个概念/类的用途是什么?
您是否曾在您的任何项目中使用过此功能,或者您有任何应使用此功能的示例?
FakeReference
或NonReference
。
Answers:
我PhantomReference
在简单,非常专业的内存分析器中使用s 来监视对象的创建和销毁。我需要他们追踪破坏。但是这种方法已经过时了。(它于2004年针对J2SE 1.4编写。)专业的分析工具功能更强大,更可靠,并且JMX或代理和JVMTI等新的Java 5功能也可以用于此目的。
PhantomReference
s(始终与Reference队列一起使用)优于s,finalize
但存在一些问题,因此应避免使用。主要是使对象再次可达。这可以通过终结器保护语来避免(->在'Effective Java'中了解更多信息)。所以它们也是新的敲定。
此外,PhantomReference
s
使您可以准确确定何时从内存中删除对象。实际上,它们是确定这一点的唯一方法。通常这没有什么用,但是在某些非常特殊的情况下(例如处理大图像)可能会派上用场:如果您确定应该对图像进行垃圾回收,则可以等到它实际加载后再尝试加载下一个图像,因此避免发生可怕的OutOfMemoryError的可能性。(引自尼古拉斯。)
一个普通切块表解释,从Java词汇。
当然,哪一个与PhantomReference文档一致:
幻影参考对象,在收集器确定可以以其他方式收回其参考对象之后将其排队。与Java终结机制相比,虚拟引用最常用于以更灵活的方式调度事前清理操作。
最后但并非最不重要的一点是所有令人毛骨悚然的细节(这是一本不错的书):Java参考对象(或我如何学会停止担心和喜欢OutOfMemoryError)。
快乐的编码。(但是要回答这个问题,我只使用过WeakReferences。)
幻影参考用法的绝佳解释:
虚拟引用是一种安全的方法,可以知道对象已从内存中删除。例如,考虑一个处理大图像的应用程序。假设当大图像已经在内存中准备好进行垃圾回收时,我们希望将大图像加载到内存中。在这种情况下,我们要等到旧图像被收集后再加载新图像。在这里,幻像引用是灵活而安全的选择。旧图像对象完成后,旧图像的引用将排队到ReferenceQueue中。收到该引用后,我们可以将新图像加载到内存中。
JAVA 9应该过时了!
使用java.util.Cleaner
,而不是!(要么sun.misc.Cleaner
在较旧的JRE上)
原始帖子:
我发现PhantomReferences的使用与终结器方法具有几乎相同的陷阱(但是一旦正确使用,问题就会更少)。我为Java 8写了一个小的解决方案(使用PhantomReferences的很小的框架)。它允许使用lambda表达式作为在对象删除后要运行的回调。您可以为应该关闭的内部资源注册回调。有了这个,我找到了一个对我有用的解决方案,因为它使它更加实用。
https://github.com/claudemartin/java-cleanup
这是一个小示例,说明如何注册回调:
class Foo implements Cleanup {
//...
public Foo() {
//...
this.registerCleanup((value) -> {
try {
// 'value' is 'this.resource'
value.close();
} catch (Exception e) {
logger.warning("closing resource failed", e);
}
}, this.resource);
}
然后有一种甚至更简单的自动关闭方法,与上述操作大致相同:
this.registerAutoClose(this.resource);
要回答您的问题:
[那么它的用途是什么]
您无法清理不存在的内容。但是它本来可以拥有仍然需要清理的资源,以便可以将其删除。
但是这个概念/类的用途是什么?
除了调试/记录外,不必执行任何其他操作。或者也许是为了统计。我认为它更像是来自GC的通知服务。您可能还想使用它来删除一旦删除对象就变得无关紧要的聚合数据(但是可能有更好的解决方案)。示例经常提到关闭数据库连接,但是我看不到这是一个好主意,因为您无法处理事务。应用程序框架将为此提供更好的解决方案。
您是否曾在您的任何项目中使用过此功能,或者您在任何示例中应使用此功能?还是仅出于面试的观点而提出这个概念;)
我主要将其用于日志记录。因此,我可以跟踪已删除的元素,并查看GC的工作方式并可以对其进行调整。我不会以这种方式运行任何关键代码。如果需要关闭某些内容,则应在try-with-resource-statement中进行。并且我在单元测试中使用它,以确保没有任何内存泄漏。和jontejj一样。但是我的解决方案比较笼统。
我在单元测试中使用了PhantomReference来验证被测代码没有保留对某些对象的不必要的引用。(原始代码)
import static com.google.common.base.Preconditions.checkNotNull;
import static org.fest.assertions.Assertions.assertThat;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import com.google.common.testing.GcFinalization;
/**
* Helps to test for memory leaks
*/
public final class MemoryTester
{
private MemoryTester()
{
}
/**
* A simple {@link PhantomReference} that can be used to assert that all references to it is
* gone.
*/
public static final class FinalizationAwareObject extends PhantomReference<Object>
{
private final WeakReference<Object> weakReference;
private FinalizationAwareObject(Object referent, ReferenceQueue<Object> referenceQueue)
{
super(checkNotNull(referent), referenceQueue);
weakReference = new WeakReference<Object>(referent, referenceQueue);
}
/**
* Runs a full {@link System#gc() GC} and asserts that the reference has been released
* afterwards
*/
public void assertThatNoMoreReferencesToReferentIsKept()
{
String leakedObjectDescription = String.valueOf(weakReference.get());
GcFinalization.awaitFullGc();
assertThat(isEnqueued()).as("Object: " + leakedObjectDescription + " was leaked").isTrue();
}
}
/**
* Creates a {@link FinalizationAwareObject} that will know if {@code referenceToKeepTrackOff}
* has been garbage collected. Call
* {@link FinalizationAwareObject#assertThatNoMoreReferencesToReferentIsKept()} when you expect
* all references to {@code referenceToKeepTrackOff} be gone.
*/
public static FinalizationAwareObject createFinalizationAwareObject(Object referenceToKeepTrackOff)
{
return new FinalizationAwareObject(referenceToKeepTrackOff, new ReferenceQueue<Object>());
}
}
和测试:
@Test
public void testThatHoldingOnToAnObjectIsTreatedAsALeak() throws Exception
{
Object holdMeTight = new String("Hold-me-tight");
FinalizationAwareObject finalizationAwareObject = MemoryTester.createFinalizationAwareObject(holdMeTight);
try
{
finalizationAwareObject.assertThatNoMoreReferencesToReferentIsKept();
fail("holdMeTight was held but memory leak tester did not discover it");
}
catch(AssertionError expected)
{
assertThat(expected).hasMessage("[Object: Hold-me-tight was leaked] expected:<[tru]e> but was:<[fals]e>");
}
}
通常WeakReference
在PhantomReference
更合适的地方使用。这样可以避免某些问题。WeakReference
了在垃圾回收器清除/排队。通常,差异并不重要,因为人们并不是在玩傻瓜。
使用PhantomReference
往往更具侵入性,因为您无法假装该get
方法有效。例如,您不能编写Phantom[Identity]HashMap
。
weakref.get
可以返回null
,然后再返回,它仍然可以返回obj?
finalize
不会像这样重新创建对象。它可以在以后使物体强可再次WeakReference
返回null
从get
和入队。/(user166390:就像在引用目标的键控映射中WeakHashMap
一样,不是引用的身份映射也可以)。
如果使用其get()方法,它将始终返回null,而不返回对象。[那么它的用途是什么]
调用(而不是get()
)的有用方法是isEnqueued()
或referenceQueue.remove()
。您将调用这些方法来执行需要在对象的最后一轮垃圾回收上执行的某些操作。
第一次是该对象finalize()
调用其方法时,因此也可以在其中放置闭合钩子。但是,正如其他人指出的那样,可能存在更肯定的执行清理的方法,或者需要在垃圾回收之前或之后进行的任何操作,或者更一般地,在对象的寿命终止时进行任何操作。
我PhantomReferences
在Jetty的LeakDetector类中发现了另一个实际用途。
Jetty使用LeakDetector
类来检测客户端代码是否获取资源但从未释放资源,并且LeakDetector
该类PhantomReferences
为此目的使用。