Java 四种引用类型,强引用、软引用、弱引用、虚引用
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
前言
每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,对于指针的使用,大家肯定记得刚学习时候的痛苦。
作为 OOP 面向对象编程的翘楚,在 Java 中一切都被视为了对象。但其实操作时候的标识符并不是真正的对象,而是对象的一个引用(reference)。
通过将这个叫“引用”的标识符指向某个对象,之后便可以使用这个引用来实现操作对象了。
在 JDK1.2 之前,Java中的定义很传统:如果 reference 类型的数据中存储的数值代表的是另外一块内存的起始地址,就称为这块内存代表着一个引用。
Java 中的垃圾回收机制在判断是否回收某个对象的时候,都需要依据“引用”这个概念。不同垃圾回收算法中,对引用的判断方式有所不同,典型的有引用计数法和可达性分析法。
JDK1.2 之前,一个对象只有“已被引用”和"未被引用"两种状态,这将无法描述某些特殊情况下的对象,比如,当内存充足时需要保留,而内存紧张时才需要被抛弃的一类对象。
所以在 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。
本篇文章将对这四种引用类型进行详细介绍。
正文
强引用
在 Java 中,我们默认声明的时候,使用的是强引用,比如:
A a = new A();
只要使用了强引用,垃圾回收器将永远不会回收被引用的对象。由于内存大小是一定的,当内存不足时,JVM 会直接抛出 OutOfMemoryError,因为没办法回收去释放空间。
如果想中断强引用与对象之间的关系,可以显示将其赋值为 null,这样一来JVM 就可以在适当的时候进行垃圾回收了。
A a = null;
软引用
软引用比强引用的程度减弱一些,表示是一些非必需但仍有用的对象。它的表现形式如下:
(1)内存足够的时候,软引用对象不会被回收。
(2)内存不足时,系统则会回收软引用对象。
如果软引用对象被回收之后,仍然没有足够的内存空间,然后会抛出内存溢出异常。
由于软引用的这种特性,非常适合实现缓存技术,比如网页缓存,图片缓存等等。
在 JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。
弱引用
弱引用的强度还要更弱一些,它最主要的特点是:无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。
在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。
我们可以用下面的小demo来测试一下:
private static void testWeakReference() { for (int i = 0; i < 10; i++) { byte[] buff = new byte[1024 * 1024]; WeakReference<byte[]> sr = new WeakReference<>(buff); list.add(sr); } System.gc(); //主动通知垃圾回收 for(int i=0; i < list.size(); i++){ Object obj = ((WeakReference) list.get(i)).get(); System.out.println(obj); } }
运行后会发现所有被弱引用关联的对象都被垃圾回收了。
在学习弱引用的时候,一个经典的例子就是 ThreadLocal,通过源代码我们发现它的内部数据结构就是由弱引用来实现的。
static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } }
在使用 ThreadLocal 时如果忘记了remove操作,很容易出现内存泄露的问题,后续有时间我会专门写一篇文章再讲讲这个。
虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收。
在 JDK1.2 之后,用 PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个 null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。
public class PhantomReference<T> extends Reference<T> { /** * Returns this reference object's referent. Because the referent of a * phantom reference is always inaccessible, this method always returns * <code>null</code>. * * @return <code>null</code> */ public T get() { return null; } public PhantomReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } }
总结
通过这篇文章介绍了 Java 语言中的四种引用类型,看完后我们发现这主要与Java 的垃圾回收机制和内存管理息息相关。JVM 作为基础,还是希望大家能够扎实的掌握。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-08-03
本文作者:程序员大帝
本文来自:“掘金”,了解相关信息可以关注“掘金”
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
5G专网,对运营商是“蜜糖”还是“砒霜”?
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 编者按:本文来自微信公众号“物联网智库”(ID:iot101),作者:赵小飞,36氪经授权发布。 给垂直行业提供定制化的网络服务以及物联网基础能力,将成为5G时代运营商To B产品的重要业态。在过去一段时间里,业界一直在探索5G赋能垂直行业的最佳方式,专网已成为5G服务垂直行业用户的核心方式之一,预计未来专网在5G时代的重要性会大大提升,不仅仅是公网的补充,甚至有可能与公网平分秋色。 此前,专网似乎与电信运营商的交集很少,然而在5G时代,积极拥抱专网,对于运营商来说是实现业务转型和扩大收入的重要举措。 领先实践,运营商积极拥抱专网 专网和公网不再是此消彼长的关系,公网运营商已将专网作为其5G核心产品。本周三,中国移动举办了一场声势浩大的“5G专网起航计划发布会”,发布了网络切片、边缘计算、专属上行等9大5G专网能力体系,推出优享、专享、尊享三类服务模式。具体来看,这三类服务包括: 优享模式:提供业务加速与业务隔离两类网络服务,满足客户对网络速率、时延以及可靠性的优先保障需求。业务加速通过...
- 下一篇
Python多继承的坑与MRO C3广度优先算法
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 前言 继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类”。继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类的行为在编译期就已经决定,无法在运行期扩展。 有些编程语言支持多重继承,即一个子类可以同时有多个父类,比如C++编程语言;而在有些编程语言中,一个子类只能继承自一个父类,比如Java编程语言,这时可以透过实现接口来实现与多重继承相似的效果。 现今面向对象程序设计技巧中,继承并非以继承类别的“行为”为主,而是继承类别的“类型”,使得组件的类型一致。另外在设计模式中提到一个守则,“多用合成,少用继承”,此守则也...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker快速安装Oracle11G,搭建oracle11g学习环境