前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java 的四种引用类型

java 的四种引用类型

作者头像
用户3147702
发布2022-06-27 12:26:38
3020
发布2022-06-27 12:26:38
举报
文章被收录于专栏:小脑斧科技博客

概述

在 java 对象存活判定算法的文章中,我们介绍了java 引用的分类。= 本文中,我们深入讨论一下四种引用究竟有什么区别,以及如何指定具体的引用方式。

正如在上面日志中介绍的,在Java中,虽然不需要程序员手动去管理对象的生命周期,但是如果希望某些对象具备一定的生命周期的话(比如内存不足时JVM就会自动回收某些对象从而避免OutOfMemory的错误)就需要用到软引用和弱引用了。

强引用

代码中普遍存在的,Object obj = new Object() 所创建的引用,只要强引用存在,垃圾收集器就永远不会回收被引用对象。 当内存不足的时候,jvm 就会抛出 OutOfMemory 错误,而不会回收强引用的对象。

强引用的断裂

只有以下两种方式可以让强引用中断,从而让 jvm 在合适的时间就会回收该对象。 1. 显式赋值为 null 会中断强引用和对象之间的关联 2. 在一个方法内部创建的对象,由于强引用保存在栈上,所引用的对象保存在堆空间中,当这个方法运行完成就会退出方法栈,从而让强引用断裂

软引用

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。 通常,软引用可用来实现内存敏感的高速缓存。

创建软引用

代码语言:javascript
复制
String str = new String("abc"); // 强引用SoftReference<String> softRef = new SoftReference<String>(str); // 软引用

适用场景

正如我们前面说的,软引用最常用的场景是高速缓存。 例如对于已经加载过的网页,如果我们通过强引用来实现,在进入新页面时,老页面就有两种选择:主动赋值为 null 或什么都不做。 如果赋值为 null,那么点击回退就必须重新加载原网页,造成体验不佳,而如果什么都不做,大量的加载过的网页停留在内存中,最终就会造成 OutOfMemory 错误。 这时,通过软引用,让已加载过的页面在内存不足时被自动回收,只要内存充足就可以任意回退而不需要重新加载,就是一个非常好的选择。

软引用队列

软引用可以配合引用队列进行使用,当软引用占有的对象被回收后,jvm 会将该软引用对象放入引用队列中。 通过软引用队列,我们可以清楚地知道程序中已有的软引用哪些已经被回收掉了。

代码语言:javascript
复制
SoftReference<T> ref = new SoftReference<T>(T t, ReferenceQueue refQueue);

通过软引用队列实现软引用缓存

我们结合软引用与软引用队列来实现一个 KV 缓存。

缓存接口 我们先来定义最基本的 KV 缓存规范接口。

只需要一个 get 接口和一个 set 接口即可。

软引用的实现 软引用只是对一个对象的引用,我们需要 K-V 的组合,因此仅仅使用软引用是不够的,需要对软引用添加额外信息,因此我们继承软引用来实现自己的软引用。

软引用缓存

我们通过 ConcurrentHashMap 实现了一个 K-V 存储,同时通过 ExtraInfoReference 设置 info 成员为 key,将软引用设置为 value 的方式记录了所有在缓存中的数据。 这样,当我们调用 get 方法发现 value 为 null 的时候,我们可以轻松地通过软引用队列来对缓存进行清理。 需要注意的是,调用 get 方法时,value = refValue.get() 会将软引用转化为强引用。

弱引用

与软引用相比,只具有弱引用的对象拥有更短暂的生命周期,不管当前内存空间是否充足,只要进行垃圾回收,弱引用的对象都会被回收。 通常只有创建时不一定会被使用到的对象应该设置为弱引用,只有当被使用到时,即通过赋值,转化为强引用,例如回调方法中的对象是一个典型场景,回调方法通常是通过匿名内部类实现的,如果他们持有外部类的强引用就造成了内存泄露。

代码语言:javascript
复制
WeakReference<T> ref = new WeakReference<T>(T t);

弱引用队列

与软引用一样,也可以通过传入 ReferenceQueue 对象指定销毁后存放的队列。

代码语言:javascript
复制
WeakReference<T> ref = new WeakReference<T>(T t, ReferenceQueue refQueue);

虚引用

虚引用也称为“幽灵引用”或“幻影引。 无法通过虚引用获取一个对象的实例,因此它的存在只能用来跟踪垃圾回收器的回收活动。 虚引用必须与引用队列联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

代码语言:javascript
复制
PhantomReference<T> ref
    = new PhantomReference<T>(T t, ReferenceQueue refQueue);

总结

四种引用类型及生存时间

引用类型

被回收时间

生存时间

备注

强引用

不会被回收

jvm 停止运行时终止

普通赋值

软引用

内存不足时回收

内存不足时 gc 后终止

通常用作对象缓存

弱引用

垃圾回收时被回收

gc 运行后终止

通常用作防止内存泄露,如匿名内部类对外部类对象的引用

虚引用

不能实例化

参考资料

深入理解 Java 虚拟机 — jvm 高级特性与最佳实践(第 2 版) https://www.cnblogs.com/gudi/p/6403953.html。 https://blog.csdn.net/jiangjiajian2008/article/details/52929843。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 强引用
    • 强引用的断裂
    • 软引用
      • 创建软引用
        • 适用场景
        • 软引用队列
          • 通过软引用队列实现软引用缓存
          • 弱引用
          • 弱引用队列
          • 虚引用
          • 总结
          • 参考资料
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档