Java语言对对象的引用有如下四种:强引用(StrongReference)、 软引用(SoftReference)、虚引用(PhantomReference)、 弱引用(WeakReference)。

1. 强引用(StrongReference)

Java中最常见的引用方式。当一个对象被一个或者一个以上的引用变量引用时,它处于激活状态,不可能被系统垃圾回收机制回收。

2. 软引用(SoftReference)

软引用需要通过SoftRefrence类来实现,当一个对象只具有软引用时,可能被垃圾回收机制回收。当系统内存空间足够时,它不会被系统回收,当系统内存空间不够时,系统将会回收。

和弱引用的区别仅仅在于垃圾回收时, 是否根据空间大小回收的区别。

何时回收软引用的对象?

从1.3.1开始软可达对象将在最后被引用之后存活一段时间。默认值是堆中每MB空闲空间一秒的生存时间。这个值可以使用-XX:SoftRefLRUPolicyMSPerMB调整。
Java Hotspot服务端虚拟机使用最大可能的堆大小计算剩余可用空间。
Java Hotspot客户端虚拟机使用当前堆大小计算空闲空间。
这就意味着对于服务端虚拟机总体趋势是增长堆而不是清理软引用,因此在垃圾回收时-Xmx对软引用的回收有重要的影响。
相反,客户端虚拟机将很大趋势去清理软引用而不是增长堆。

上述行为对于1.3.1到Java SE 6版本的Java HotSpot VM都是正确的。但是,此行为不是VM规范的一部分,并且在将来的版本中可能会更改。同样,不保证-XX:SoftRefLRUPolicyMSPerMB标志在任何给定的发行版中均不存在。

在1.3.1版之前,Java HotSpot VM会在发现软引用时清除它们。

当我定期打开-verbose:gc时,我得到了很多完整的GC,已经调整了堆并且没有什么区别,这是怎么回事?

如果您使用的是RMI,则可能会遇到分布式GC。另外,某些应用程序添加了显式GC的思想,即它将使它们的应用程序更快。幸运的是,您可以在1.3及更高版本中使用命令行选项禁用此功能。尝试将-XX:+ DisableExplicitGC与-verbose:gc一起使用,看看是否有帮助。

3. 虚引用(PhantomReference)

虚引用通过PhantomReference实现,虚引用类似于完全没有引用,虚引用对对象本身没有太大的影响。虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和引用队列(ReferenceQueue)联合使用。

举例来说就是,如果垃圾回收时,发现一个实例对象除了虚引用外没有任何其他的引用,将会把这个引用放到
java.lang.ref.Reference.pending队列里,GC完成时,通知ReferenceHandler这个守护线程做一些后续处理(如释放内存等等操作)。

4. 弱引用(WeakReference)

弱引用通过WeakReference类实现,对只有弱引用的对象而言,当系统垃圾回收机制运行时,不管内存是否足够,总会回收该对象所占用的内存。

4.1 示例

1
2
3
ReferenceQueue referenceQueue = new ReferenceQueue();
WeakReference weakReference = new WeakReference(new TestEntity(), referenceQueue);
((TestEntity) weakReference.get()).test();

ReferenceQueue的作用是为了查看哪些WeakReference和SoftReferece被回收了。

参考资料

疯狂Java讲义

Java PhantomReference详解

Frequently Asked Questions About the Java HotSpot VM