JAVA中的四种引用(Reference)

概述

在 jdk 1.2 及其以后,引入了强引用、软引用、弱引用、虚引用这四个概念。网上很多关于这四个概念的解释,但大多是概念性的泛泛而谈,今天我结合着代码分析了一下,首先我们先来看定义与大概解释(引用类型在包 Java.lang.ref 里)。

Java中一共有四种Reference, 其中 SoftReference, WeakReference, PhantomReference内有一个Referent和ReferenceQueue

  • Referent: 被引用对象

  • RefernceQueue: 当引用的Referent被回收后该引用会被enqueue到这个ReferenceQueue中

一个对象可以同时拥有多种引用, 可以通过Reference.get()方法获取Referent

强引用(StrongReference)

强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型。举个例子来说:

1
    Object obj = new Object();

这里的obj引用便是一个强引用,不会被GC回收。

软引用(SoftReference)

软引用在JVM报告内存不足的时候才会被GC回收,否则不会回收,正是由于这种特性软引用在caching和pooling中用处广泛。

软引用的用法:

1
2
3
4
Object obj = new Object();
    SoftReference<Object> softRef =new SoftReference(obj);
    // 使用 softRef.get() 获取软引用所引用的对象
    Object objg = softRef.get();

弱引用(WeakReference)

当GC一但发现了弱引用对象,将会释放WeakReference所引用的对象。弱引用使用方法与软引用类似,但回收策略不同。

1
2
3
4
Object obj = new Object();
    WeakReference<Object> WeakRef =new WeakReference(obj);
    // 使用 WeakRef.get() 获取软引用所引用的对象
    Object objg = WeakRef.get();

虚引用(PhantomReference)

当GC一但发现了虚引用对象,将会将PhantomReference对象插入ReferenceQueue队列,而此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收。虚引用的用法:

1
2
3
4
5
6
7
8
9
10

Object obj = new Object();
ReferenceQueue<Object> refQueue =new ReferenceQueue<Object>();
PhantomReference<Object> phanRef =new PhantomReference<Object>(obj, refQueue);
// 调用phanRef.get()不管在什么情况下会一直返回null
Object objg = phanRef.get();
// 如果obj被置为null,当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列
// 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后
// 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收
Reference<? extends Object> phanRefP = refQueue.poll();

ReferenceQueue (引用队列)

如果Reference在构造方法加入ReferenceQueue参数, Reference在它的Referent被GC的时,会将这个Reference加入ReferenceQueue

WeakHashMap

WeakHashMap是HashMap的WeakReference实现, 他使用WeakReference封装了Entry的Key, 如果这个WeakHashMap的key仅有这个Map持有弱引用,则当JVM GC执行时,它的key和value会被GC. 如果这个key还有别的引用则不会被GC.

1
2
3
4
5
WeakHashMap<Object, String> map = new WeakHashMap<Object, String>();
map.put(new Object(), "test");
System.out.println(map);
System.gc();
System.out.println(map);

拓展阅读

Java 中的 Reference (4种引用类型) - hbzh2008的专栏 - CSDN博客
Java Reference - ZimZz - 博客园

戴定康 wechat
欢迎您扫一扫上面的微信,加我为好友!