java中的强引用、软引用、弱引用和虚引用

50 阅读3分钟

一、前言

在java中,对象的引用被划分为四种级别,这四种级别由高到低依次为:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种。

强引用(Strong Reference)

强引用在java中是最常见的,把一个对象赋值给一个引用变量,这个引用变量就是一个强引用。如果一个对象被强引用变量引用着,那么这个对象处于可达状态,是不会被垃圾回收机制回收的。

Object obj = new Object();

即使是内存不足,java虚拟机宁愿抛出OutOfMemoryError,使程序终止,也不会回收具有强引用的对象来解决内存不足的问题。

我们来分析一个代码:

public static void main(String[] args) {
        Object obj = new Object();
}

main方法运行,main方法对应的栈帧入栈,obj为对象的引用变量,存放在栈帧里面,真正的对象(new Object())是存放在堆里面的,main方法运行结束,对应的栈帧就会出栈,则这个栈帧里面的引用就会随之销毁,则引用对象的引用数量就会归0,那么这个对象就会被回收。

我们可以显示地将对象置空(null),那么垃圾收集器就会认为该对象不存在引用,这时就可以回收该对象。

obj = null;

软引用(Soft Reference)

软引用需要用SoftReference类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。以下为代码示例:

String str = new String("hello world");
SoftReference<String> softReference = new SoftReference<>(str);

软引用通常用在对内存敏感的程序中,比如高速缓存。

弱引用(Weak Reference)

弱引用需要用WeakReference类来实现,它比软引用的生存周期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存。以下为代码示例:

String str = new String("hello world");
WeakReference<String> weakReference = new WeakReference<>(str);

虚引用(PhantomReference)

虚引用需要使用PhantomReference类来实现,不能单独使用,需要和引用队列来联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态。

虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

String str = new String("hello world");
//创建引用队列
ReferenceQueue<Object> queue = new ReferenceQueue<>();
//创建虚引用,需要跟一个引用队列来关联
PhantomReference pr = new PhantomReference(str, queue);

下面我们来用一张图进行总结:

引用类型被垃圾回收时间用途生存时间
强引用从来不会对象的一般状态JVM停止运行时终止
软引用当内存不足时对象缓存内存不足时终止
正常垃圾回收时对象缓存垃圾回收后终止
虚引用正常垃圾回收时跟踪对象的垃圾回收垃圾回收后终止