问题描述
直到今天,我才意识到 Java 有四种主要类型的引用。
-
强引用:
Java
使用的默认引用类型。 -
弱引用:如果一个对象有一个弱引用,那么即使有足够的内存,
GC
也会在下次运行时回收这个对象的内存。 -
软引用:如果一个对象有一个软引用,那么
GC
只会在它非常需要一些内存时才回收这个对象的内存。 -
幻像引用:如果一个对象有一个幻像引用,那么它就有资格进行垃圾回收。但是,在 GC 之前,JVM 将应该被垃圾回收的对象放入名为
reference queue
的队列中。
我理解了基本概念,并编写了一个小程序来了解每种引用类型的工作原理。
import java.lang.ref.Phantomreference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.softReference;
import java.lang.ref.WeakReference;
class User
{
public User info()
{
System.out.println("Info method invoked from User class");
return null;
}
}
public class ReferencesExample
{
public static void main(String[] args)
{
//Strong Reference
User userRefObj = new User();
System.out.println("1 :" + userRefObj.info());
// Weak Reference
WeakReference<User> weakref = new WeakReference<User>(userRefObj.info());
System.out.println("2 : " + weakref);
// Soft Reference
SoftReference<User> softref = new SoftReference<User>(userRefObj.info());
System.out.println("3 : " + softref);
// Phantom Reference
ReferenceQueue<User> refQueueObj = new ReferenceQueue<User>();
Phantomreference<User> phantomref = new Phantomreference<User>(userRefObj.info(),refQueueObj);
System.out.println("4 : " + phantomref);
}
}
输出:
1 :null
Info method invoked from User class
Info method invoked from User class
2 : java.lang.ref.WeakReference@15db9742
Info method invoked from User class
3 : java.lang.ref.softReference@6d06d69c
Info method invoked from User class
4 : java.lang.ref.Phantomreference@7852e922
疑问:我们如何决定在实际场景中使用哪种引用类型以及在何处使用?
解决方法
事实的答案非常简单:因为仅靠强引用是不够的。在现实世界的生产代码中,您肯定需要一些弱引用的概念。
然后可以争辩说其他类型只是过度工程化。该语言的设计者认为这些是有帮助的,但除了非常模糊的情况外,它们并非如此。但注意:对应的语义无法用普通的java代码来完成。所以这是其中一种情况“让我们将它添加到语言中,以防我们需要它”。
但第二段很容易被视为意见,而不是事实。
,这是一个复杂的答案,尤其是“现实世界”部分。这些特殊的参考文献是一个(非常)锋利的工具,应该很少接触并且有很好的理解。您的第一个误解是只有 Phantom References
使用 queue
(称为 ReferenceQueue
)。事实上,他们都使用queue
。其中,PhantomReference
有点“怪人”,主要是因为围绕它的规范已经从 java-8
变成了 java-9
。您可以阅读 this answer to get some details(目前尚不清楚在 java-8
中保持实例活动的原因)。
然后您得到的常见误解是“下一次运行”,有关更多详细信息,您可以take a look here。这里的“第二个”或“下一个”的概念有点棘手;但关键是这是不确定的。
提供“真实世界”的例子也有点棘手。发生这种情况是因为您很少直接使用这些引用,它们通常预先打包在实用程序中。例如,您可以使用 take a look of how WeakHashMap 工作(直接在引擎盖下使用 WeakReference
和 ReferenceQueue
)或事件 this answer。 guava
及其 CacheBuilder
用于提供一些处理 SoftReferences
(但不再是)、caffeine still does though 的功能。
PhantomReferences
在内部用于 Cleaner API
(自 java-9
)。 here 是显示其一般用法的示例。没有 PhantomReferences
,这真的不可能(至少不是那么“容易”)。
就此而言,我们在生产中使用 WeakHashMap
(我们也使用 Cleaner API
,但要少得多)。如果您真的想了解它们,您需要了解 garbage collector
的工作原理(例如,真的 工作),然后阅读他们的官方文档并尝试(并询问)多种方法。