Java 你曾经在任何项目中使用过 PhantomReference 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1599069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Have you ever used PhantomReference in any project?
提问by Rakesh Juyal
The only thing I know about PhantomReference
is,
我唯一知道的PhantomReference
是,
- If you use its
get()
method, it will always returnnull
and not the object. What's the use of it? - By using
PhantomReference
, you make it sure that the object cannot be resurrected fromfinalize
method.
- 如果您使用它的
get()
方法,它将始终返回null
而不是对象。它有什么用? - 通过使用
PhantomReference
,您可以确保对象无法从finalize
方法中复活。
But what is the use of this concept/class?
Have you ever used this in any of your project or do you have any example where we should use this?
但是这个概念/类有什么用呢?
你有没有在你的任何项目中使用过它,或者你有任何我们应该使用它的例子吗?
采纳答案by Peter Kofler
I used PhantomReference
s in a simplistic, very specialized kind of memory profilerto monitor object creation and destruction. I needed them to keep track of destruction. But the approach is out-dated. (It was written in 2004 targeting J2SE 1.4.) Professional profiling tools are much more powerful and reliable and the newer Java 5 features like JMX or agents and JVMTI can be used for that too.
我PhantomReference
在一个简单的、非常专业的内存分析器中使用s来监视对象的创建和销毁。我需要它们来跟踪破坏。但这种方法已经过时了。(它是在 2004 年针对 J2SE 1.4 编写的。)专业的分析工具更加强大和可靠,更新的 Java 5 特性,如 JMX 或代理和 JVMTI 也可以用于这一点。
PhantomReference
s (always used together with the Reference queue) are superior to finalize
which has some problems and should therefore be avoided. Mainly making objects reachable again. This could be avoided with the finalizer guardian idiom (-> read more in 'Effective Java'). So they are also the new finalize.
PhantomReference
s(总是与引用队列一起使用)优于finalize
which 有一些问题,因此应该避免。主要是使对象再次可达。这可以通过终结器监护人习语来避免(-> 阅读“Effective Java”中的更多内容)。所以他们也是新的敲定。
Furthermore, PhantomReference
s
此外,PhantomReference
s
allow you to determine exactly when an object was removed from memory. They are in fact the only way to determine that. This isn't generally that useful, but might come in handy in certain very specific circumstances like manipulating large images: if you know for sure that an image should be garbage collected, you can wait until it actually is before attempting to load the next image, and therefore make the dreaded OutOfMemoryError less likely. (Quoted from enicholas.)
允许您准确确定对象何时从内存中删除。它们实际上是确定这一点的唯一方法。这通常不是那么有用,但在某些非常特殊的情况下可能会派上用场,例如操作大图像:如果您确定应该对图像进行垃圾收集,则可以等到它实际完成后再尝试加载下一张图像,因此降低了可怕的 OutOfMemoryError 的可能性。(引自enicholas。)
And as psdwrote first, Roedy Green has a good summary of references.
回答by Rakesh Juyal
A general diced-up table explanation, from the Java Glossary.
一个普通切块表的解释,从Java词汇。
Which of course coincides with the PhantomReference documentation:
这当然与PhantomReference 文档一致:
Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed. Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.
Phantom 引用对象,在收集器确定它们的引用对象可能会被回收后入队。幻像引用最常用于以比 Java 终结机制更灵活的方式调度预检清理操作。
And last but not least, all the gory details (this is a good read): Java Reference Objects (or How I Learned to Stop Worrying and Love OutOfMemoryError).
最后但并非最不重要的,所有血腥的细节(这是一个很好的阅读):Java 参考对象(或我如何学会停止担心和爱 OutOfMemoryError)。
Happy coding. (But to answer the question, I've only ever used WeakReferences.)
快乐编码。(但为了回答这个问题,我只使用过 WeakReferences。)
回答by Tom Hawtin - tackline
It is common to use WeakReference
where PhantomReference
is more appropriate. This avoids certain problems of being able to resurrect objects after a WeakReference
is cleared/enqueued by the garbage collector. Usually the difference doesn't matter because people are not playing silly buggers.
通常WeakReference
在PhantomReference
更合适的地方使用。这避免WeakReference
了在垃圾收集器清除/入队后能够复活对象的某些问题。通常差异并不重要,因为人们不是在玩愚蠢的家伙。
Using PhantomReference
tends to be a bit more intrusive because you can't pretend that the get
method works. You can't, for example, write a Phantom[Identity]HashMap
.
使用PhantomReference
往往更具侵入性,因为您无法假装该get
方法有效。例如,您不能编写Phantom[Identity]HashMap
.
回答by Tan Hui Onn
I found a practical and useful use case of PhantomReference
which is org.apache.commons.io.FileCleaningTracker
in commons-io project. FileCleaningTracker
will delete the physical file when its marker object is garbage collected.
Something to take note is the Tracker
class which extends PhantomReference
class.
我发现了一个实用和有用的用例PhantomReference
是org.apache.commons.io.FileCleaningTracker
在公共-io的项目。FileCleaningTracker
将在其标记对象被垃圾收集时删除物理文件。
需要注意的是Tracker
扩展PhantomReference
类的类。
回答by jontejj
I used a PhantomReference in a unit test to verify that the code under test didn't keep unnessecary references to some object. (Original code)
我在单元测试中使用了 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>());
}
}
And the test:
和测试:
@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>");
}
}
回答by Sergii Shevchyk
Great explanationof Phantom Reference usage:
Phantom Reference 用法的精彩解释:
Phantom references are safe way to know an object has been removed from memory. For instance, consider an application that deals with large images. Suppose that we want to load a big image in to memory when large image is already in memory which is ready for garbage collected. In such case, we want to wait until the old image is collected before loading a new one. Here, the phantom reference is flexible and safely option to choose. The reference of the old image will be enqueued in the ReferenceQueue once the old image object is finalized. After receiving that reference, we can load the new image in to memory.
幻像引用是知道对象已从内存中删除的安全方式。例如,考虑一个处理大图像的应用程序。假设我们想要在大图像已经在内存中准备好进行垃圾收集时将大图像加载到内存中。在这种情况下,我们希望等到旧图像被收集后再加载新图像。在这里,虚拟参考是灵活且安全的选择。一旦旧图像对象完成,旧图像的引用将在 ReferenceQueue 中排队。收到该引用后,我们可以将新图像加载到内存中。
回答by Claude Martin
THIS SHOULD BE OBSOLETE WITH JAVA 9!
Use java.util.Cleaner
instead! (Or sun.misc.Cleaner
on older JRE)
这应该在 JAVA 9 中过时了!
使用java.util.Cleaner
,而不是!(或sun.misc.Cleaner
在较旧的 JRE 上)
Original post:
原帖:
I found that the use of PhantomReferences has nearly the same amount of pitfalls as finalizer methods (but a fewer problems once you get it right). I have written a small solution (a very small framework to use PhantomReferences) for Java 8. It allows to use lambda expressions as callbacks to be run after the object has been removed. You can register the callbacks for inner resources that should be closed. With this I have found a solution that works for me as it makes it much more practical.
我发现 PhantomReferences 的使用与终结器方法有几乎相同数量的陷阱(但一旦你做对了,问题就会更少)。我为 Java 8 编写了一个小解决方案(一个使用 PhantomReferences 的非常小的框架)。它允许使用 lambda 表达式作为在对象被删除后运行的回调。您可以为应该关闭的内部资源注册回调。有了这个,我找到了一个对我有用的解决方案,因为它使它更实用。
https://github.com/claudemartin/java-cleanup
https://github.com/claudemartin/java-cleanup
Here's a small example to show how a callback is registered:
下面是一个小例子来展示回调是如何注册的:
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);
}
And then there is the even simpler method for auto-close, doing about the same as the above:
然后还有更简单的自动关闭方法,与上面的操作大致相同:
this.registerAutoClose(this.resource);
To answer your questions:
回答您的问题:
[ then whats the use of it ]
【那有什么用】
You can't clean up something that doesn't exist. But it could have had resources that still exist and need to be cleaned up so they can be removed.
你无法清理不存在的东西。但它可能有仍然存在的资源,需要清理,以便可以将其删除。
But what is the use of this concept/class?
但是这个概念/类有什么用呢?
It's not necessarily to do anything with any effect other than debugging/logging. Or maybe for statistics. I see it more like a notification service from the GC. You could also want to use it to remove aggregated data that becomes irrelevant once the object is removed (but there are probably better solutions for that). Examples often mention database connections to be closed, but I don't see how this is such a good idea as you couldn't work with transactions. An application framework will provide a much better solution for that.
除了调试/记录之外,不一定要做任何有任何影响的事情。或者也许是为了统计。我认为它更像是来自 GC 的通知服务。您还可以使用它来删除对象被删除后变得不相关的聚合数据(但可能有更好的解决方案)。示例经常提到要关闭的数据库连接,但我看不出这是一个好主意,因为您无法使用事务。应用程序框架将为此提供更好的解决方案。
Have you ever used this in any of your project, or do you have any example where we should use this? Or is this concept made just for interview point of view ;)
你有没有在你的任何项目中使用过这个,或者你有任何我们应该使用它的例子吗?或者这个概念只是为了面试的观点;)
I use it mostly just for logging. So I can trace the removed elements and see how GC works and can be tweaked. I wouldn't run any critical code in this way. If something needs to be closed then it should be done in a try-with-resource-statement. And I use it in unit tests, to make sure I don't have any memory leaks. The same way as jontejj does it. But my solution is a bit more general.
我主要使用它来记录日志。所以我可以跟踪删除的元素,看看 GC 是如何工作的,并且可以进行调整。我不会以这种方式运行任何关键代码。如果需要关闭某些内容,则应在 try-with-resource-statement 中完成。我在单元测试中使用它,以确保我没有任何内存泄漏。和 jontejj 一样。但我的解决方案更通用一些。
回答by Claude Martin
if you use its get() method it will always return null, and not the object. [ then whats the use of it ]
如果您使用它的 get() 方法,它将始终返回 null,而不是对象。【那有什么用】
The useful methods to call (rather than get()
) would be isEnqueued()
or referenceQueue.remove()
. You would call these methods to perform some action that needs to take place on the final round of garbage collection of the object.
调用(而不是get()
)的有用方法是isEnqueued()
or referenceQueue.remove()
。您将调用这些方法来执行一些需要在对象的最后一轮垃圾收集中发生的操作。
The first time around is when the object has its finalize()
method called, so you could put closing hooks there too. However, as others have stated, there are probably more sure ways of performing clean up or whatever action needs to take place pre and post garbage collection or, more generally, upon end-of-life of the object.
第一次是在对象finalize()
调用其方法时,因此您也可以在那里放置关闭钩子。然而,正如其他人所说,可能有更可靠的方法来执行清理或任何需要在垃圾收集前后或更一般地说,在对象生命周期结束时进行的操作。
回答by Sahil Chhabra
I found another practical use of PhantomReferences
in LeakDetectorclass of Jetty.
我PhantomReferences
在Jetty 的LeakDetector类中发现了另一个实际用途。
Jetty uses LeakDetector
class to detect if the client code acquires a resource but never releases it and the LeakDetector
class uses the PhantomReferences
for this purpose.
Jetty 使用LeakDetector
类来检测客户端代码是否获取了资源但从不释放它,LeakDetector
类PhantomReferences
为此目的使用 。