Java中的引用类型

2020-06-18 Java

Java提供的4种引用类型,它们分别是强引用(StrongReference)软引用(SoftReference)弱引用(WeakReference)幽灵引用(PhantomReference)

强引用(StrongReference)

强引用是Java编程中最普遍的引用,例如Objectobj=newObject()中,新建的Object对象就是被强引用的。

如果一个对象被强引用,即使是Java虚拟机内存空间不足时,GC(垃圾收集器)也绝不会回收该对象。

Java虚拟机内存不足时,就可能会导致内存溢出,我们常见的就是OutOfMemoryError异常。

软引用(SoftReference)

软引用是引用强度仅弱于强引用的一种引用,它使用类SoftReference来表示。

Java虚拟机内存不足时,GC会回收那些只被软引用指向的对象,从而避免内存溢出。

GC释放了那些只被软引用指向的对象之后,虚拟机内存依然不足,才会抛出OutOfMemoryError异常。

软引用适合引用那些可以通过其他方式恢复的对象,例如,数据库缓存中的对象就可以从数据库中恢复,所以软引用可以用来实现缓存。
另外,由于在程序使用软引用之前的某个时刻,其所指向的对象可能已经被G·C回收掉了,所以通过Reference.get()方法来获取软引用所指向的对象时,总是要通过检查该方法返回值是否为null,来判断被软引用的对象是否还存活。

引用队列 (ReferenceQueue )

在很多场景下,我们的程序需要在一个对象的可达性(是否己经被GC回收)发生变化时得到通知,引用队列就是用于收集这些信息的队列。

在创建SoftReference对象时,可以为其关联一个引用队列,当SoftReference所引用的对象被GC回收时,Java虚拟机就会将该SoftReference对象添加到与之关联的引用队列中。

当需要检测这些通知信息时,就可以从引用队列中获取这些SoftReference对象。不仅是SoftReference,下面介绍的弱引用和幽灵引用都可以关联相应的队列。

弱引用(WeakReference)

弱引用的强度比软引用的强度还要弱。弱引用使用WeakReference来表示,它可以引用一个对象,但并不阻止被引用的对象被GC回收。在JVM虚拟机进行垃圾回收时,如果指向一个对象的所有引用都是弱引用,那么该对象会被回收。

由此可见,只被弱引用所指向的对象的生存周期是两次GC之间的这段时间,而只被软引用所指向的对象可以经历多次GC,直到出现内存紧张的情况才被回收。
弱引用典型的应用情景是就是JDK提供的java.util.WeakHashMapWeakHashMap.Entry实现继承了WeakReferenceEntry弱引用key,强引用value

image-20200618214631511

当不再由强引用指向key时,则key可以被垃圾回收,当key被垃圾回收之后,对应的Entry对象会被Java虚拟机加入到其关联的队列中。

当应用程序下次操作WeakHashMap时,例如对WeakHashMap的扩容操作,就会遍历关联的引用队列,将其中的Entry对象从WeakHashMap中删除。

幽灵引用(PhantomReference)

在介绍幽灵引用之前,要先了解一下Java提供的对象终止化机制。

Object类里面有个finalize()方法,设计该方法的初衷是在一个对象被真正回收之前,执行一些清理工作,但由于GC的运行时间是不固定的,所以这些清理工作的实际运行时间也是无法预知的,而且JVM虚拟机不能保证finalize()方法一定会被调用。

每个对象的finalize()方法至多由GC执行一次,对于再生对象GC不会再次调用其finalize()方法。另外,使用finalize()方法还会导致严重的内存消耗和性能损失。

由于finalize()方法存在的种种问题,该方法现在已经被废弃,而我们可以使用幽灵引用实现其替代方案。

幽灵引用,又叫“虚引用”,它是最弱的一种引用类型,由类PhantomReference表示。在引用的对象未被GC回收时,调用前面介绍的SoftReference以及WeakReferenceget()方法,得到的是其引用的对象;当引用的对象已经被GC回收时,则得到null。但是PhantomReference.get()方法始终返回null

在创建幽灵引用的时候必须要指定一个引用队列。当GC准备回收一个对象时,如果发现它还有幽灵引用,就会在回收对象的内存之前,把该虚引用加入到与之关联的引用队列中。

程序可以通过检查该引用队列里面的内容,跟踪对象是否己经被回收并进行一些清理工作。幽灵引用还可以用来实现比较精细的内存使用控制,例如应用程序可以在确定一个对象要被回收之后,再申请内存创建新对象,但这种需求并不多见。

Java

相关推荐



版权声明




文章目录