java reference_Java中的Reference

Java中的Reference

1. 常用四种引用

快速记忆法:“硬(俗称的强引用) --> 软(SoftReference) --> 弱(WeakReference) --> 虚(PhantomReference)”

此处将常说的“强引用”记忆成“硬引用”可以对应到次席的“软引用”(反义词:硬-软)这样更容易记住

a. 强引用

平常我们代码中写到的引用类型都是强引用类型,比如Object obj = new Object();, Object实例就有一个强引用类型指向它,在GC过程中即使发生OOM,该Object实例都不会被回收。

b. 软引用 - SoftReference

定义方式:SoftReference sr = new SoftReference(new Object()); 一个对象的实例被一个软引用实例指向,那么在GC过程中发生OOM之前,该Object对象实例会被回收掉,在内存充足的情况下是不会被回收的。同时可以将一个引用队列关联到该软引用上,在软引用指向的对象被回收后,该软引用会被加入到关联的引用队列中。我们可以通过Reference的get()方法获取到该软引用指向的对象实例。

c. 弱引用 - WeakReference

弱引用基本上同上面的软引用类似,WeakReference wr = new WeakReference(new Object());,但是特殊点就是在它被创建后的下一次GC时候其指向的对象实例会被回收掉,不管内存是不是充足,反正就是活不过一次GC。JDK中的WeakHashMap就是使用到WeakReference,其Key就是被包装成WeakReference。

d. 虚引用 - PhantomReference

定义方式:PhantomReference pr = new PhantomReference(new Object(), new ReferenceQueue()),虚引用对象再被定义时,必须指定一个引用队列实例。JDK文档中介绍它主要用于对象被回收前资源的释放操作,替换finalize()方法。它和前面的两个软引用和弱引用不同的地方有两点:

9f941e1868e7e29f9caa1d1734b89181.png

2. 验证

虚引用在对象被回收之前添加到引用队列中,同时需要手动处理,它指向的对象才会被回收

思路:

a. 创建一个虚引用对象,然后发起一次GC操作,查看其指向的对象实例是否被回收

b. 通过检测它关联的引用队列,取出加入的虚引用对象,查看此时其指向的对象实例是否被回收

c. 调用虚引用对象的clear方法之后,查看其指向的对象实例是否被回收

2.1. 代码

public class ReferenceApp1 {

public static void main(String[] args) throws Exception {

phantom();

}

/**

* 验证PhantomReference

* @throws Exception

*/

private static void phantom() throws Exception {

// 步骤1. 定义一个InnerPhantomRefObj对象实例

InnerPhantomRefObj innerPhantomRefObj = new InnerPhantomRefObj();

innerPhantomRefObj.setName("InnerPhantomRefObj-1");

ReferenceQueue referenceQueue = new ReferenceQueue<>();

// 步骤2. 定义一个虚引用对象

PhantomReference phtRef = new PhantomReference<>(innerPhantomRefObj, referenceQueue);

// 移除InnerPhantomRefObj对象实例上的强引用,不然后面操作不会被回收

innerPhantomRefObj = null;

System.err.println("before gc | get PhantomReference referent:" + phtRef.get());

// 步骤3. 发起GC操作

System.gc();

int i = 0;

Reference tmp = null;

while(true) {

System.out.println("phantom iteration >>>> " + ++i);

Thread.sleep(5000);

if(i == 1) {

// 步骤4. 从引用队列中取出虚引用对象

tmp = referenceQueue.poll();

if(tmp != null) {

System.err.println("get PhantomReference from ReferenceQueue");

}

// 发起一次GC操作,其实此时InnerPhantomRefObj对象不会被回收

System.gc();

}

if(i == 5) {

if(tmp != null) {

System.err.println("after gc | get PhantomReference referent:" + tmp.get());

// 步骤5. 调用虚引用上的clear方法,让下一次GC操作回收掉InnerPhantomRefObj对象

tmp.clear();

// 或者让GC操作释放PhantomReference对象实例

// tmp = null;

// phtRef = null;

System.err.println("clear PhantomReference");

// 发起一次GC操作

System.gc();

}

}

if(i == 10) {

break;

}

}

}

@Data

private static class InnerPhantomRefObj {

private String name;

}

}

2.2. 观察VisualVM中实例个数变化判断是否被回收

a. 从上述代码的步骤1到步骤5之间的实例统计截图如:(实例个数为1,没有被回收)

842641a95309afc7fde6f99d5bc65c2d.png

b. 执行步骤5(调用PhantomReference的clear方法)之后的实例统计截图如:(实例个数为0,已被被回收)

df2bec124894ea3724c4dbac7d969df1.png

3. 类比

看到一篇英文博客中用一个例子来类比软、弱、虚引用三者之间的差别非常好,在此借用一下:

比如一个快餐店中,桌子座位有限,服务员会随时清理桌子座位,你进去点单,找到一个座位坐下,会存在下面几种情况

a. 然后后面有很多人过来点单时,当座位不够时你会让出座位,但在此之前每次服务员过来清理座位时你都没有让出座位,这种情况就像就像软引用

b. 第一次服务员过来清理桌子座位时,你就让出座位,这种情况就像弱引用

c. 第一次服务员过来清理桌子座位时,你可以随时准备让出座位,其实这时候你并没有让出位置,但是后面服务员说出一句让你让出座位时你才会让出座位,这种情况就像虚引用

作者:sv

出处:https://www.cnblogs.com/sv00

版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值