Java强软弱虚四种引用,看完不再犯迷糊
其实强引用、软引用、弱引用、虚引用这四个概念非常简单好记。
在开头先总结一下这四个引用的特点吧。
强引用:gc时不会回收
软引用:只有在内存不够用时,gc才会回收
弱引用:只要gc就会回收
虚引用:是否回收都找不到引用的对象,仅用于管理直接内存
接下来详细看看这四种引用,结合代码,深刻的体会一下。
强引用
即我们平时最常见的:
Object object = new Object();
只要一个对象有强引用,垃圾回收器就不会进行回收。即便内存不够了,抛出OutOfMemoryError异常也不会回收。
上demo,注意注释
/** * 一个对象 * 重写finalize方法,可以知道已经被回收的状态 * * @author * @date 2020-05-23 */ public class OneObject { @Override protected void finalize() throws Throwable { System.out.println("啊哦~OneObject被回收了"); } } /** * 强引用例子 * * @author * @date 2020-05-23 */ public class ShowStrongReference { public static void main(String[] args) { // 直接new一个对象,就是强引用 OneObject oneObject = new OneObject(); System.out.println("输出对象地址:" + oneObject); System.gc(); System.out.println("第一次gc后输出对象地址:" + oneObject); oneObject = null; System.gc(); System.out.println("置为null后gc输出对象地址:" + oneObject); } }
执行代码,可以看到以下输出:
输出对象地址:com.esparks.pandora.learning.references.OneObject@72ea2f77 第一次gc后输出对象地址:com.esparks.pandora.learning.references.OneObject@72ea2f77 置为null后gc输出对象地址:null 啊哦~OneObject被回收了
软引用
需要通过SoftReference对象实现:
SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());
当内存足够的时候,垃圾回收器不会进行回收。当内存不够时,就会回收只存在软引用的对象释放内存。
常用于本地缓存处理。
上demo,注意注释
/** * 软引用 * 内存不够了就会回收 * 注意,运行时需要保证heap大小为35m,即小于实验中全部对象的大小,才能触发gc * -Xmx35m * * @author * @date 2020-05-23 */ public class ShowSoftReference { public static void main(String[] args) { // 我们需要通过SoftReference来创建软引用 SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject()); // 我们这里创建一个大小为20m的数组 SoftReference<byte[]> arraySr = new SoftReference<>(new byte[1024 * 1024 * 20]); System.out.println("软引用对象oneObjectSr的地址:" + oneObjectSr); System.out.println("通过oneObjectSr关联的oneObject对象的地址:" + oneObjectSr.get()); System.out.println("数组的地址:" + arraySr.get()); System.gc(); System.out.println("正常gc一次之后,oneObject对象并没有回收。地址" + oneObjectSr.get()); // 再创建另一个大小为20m的数组,这样heap就不够大了,从而系统自动gc。如果依旧不够,会把已有的软引用关联的对象都回收掉。 System.out.println("创建另一个大小为20m的数组otherArray"); byte[] otherArray = new byte[1024 * 1024 * 20]; System.out.println("otherArray的地址:" + otherArray); // gc后,软引用对象还在,但是通过软引用对象创建的对象就被回收了 System.out.println("现在srObject的地址:" + arraySr); System.out.println("现在srObject中oneObject对象的地址:" + arraySr.get()); System.out.println("刚才的数组对象也被回收啦,地址:" + arraySr.get()); } }
执行代码,可以看到以下输出:
软引用对象oneObjectSr的地址:java.lang.ref.SoftReference@72ea2f77 通过oneObjectSr关联的oneObject对象的地址:com.esparks.pandora.learning.references.OneObject@33c7353a 数组的地址:[B@681a9515 正常gc一次之后,oneObject对象并没有回收。地址com.esparks.pandora.learning.references.OneObject@33c7353a 创建另一个大小为20m的数组otherArray 啊哦~OneObject被回收了 otherArray的地址:[B@3af49f1c 现在srObject的地址:java.lang.ref.SoftReference@19469ea2 现在srObject中oneObject对象的地址:null 刚才的数组对象也被回收啦,地址:null
弱引用
需要通过WeakReference对象实现:
WeakReference<OneObject> oneObjectWr = new WeakReference<>(new OneObject());
只要发生gc,就会回收只存在弱引用的对象。
常用于Threadlocal。
上demo,注意注释
/** * 弱引用 * 只要gc就会回收 * * @author * @date 2020-05-23 */ public class ShowWeakReference { public static void main(String[] args) { // 我们需要通过WeakReference来创建弱引用 WeakReference<OneObject> objectWr = new WeakReference<>(new OneObject()); System.out.println("弱引用objectWr的地址:" + objectWr); System.out.println("弱引用objectWr关联的oneObject对象的地址:" + objectWr.get()); System.gc(); // gc后,弱引用对象还在,但是通过弱引用对象创建的对象就被回收了 System.out.println("gc后,弱引用objectWr的地址:" + objectWr); System.out.println("gc后,弱引用objectWr关联的oneObject对象的地址:" + objectWr.get()); } }
执行代码,可以看到以下输出:
弱引用objectWr的地址:java.lang.ref.WeakReference@72ea2f77 弱引用objectWr关联的oneObject对象的地址:com.esparks.pandora.learning.references.OneObject@33c7353a gc后,弱引用objectWr的地址:java.lang.ref.WeakReference@72ea2f77 gc后,弱引用objectWr关联的oneObject对象的地址:null 啊哦~OneObject被回收了
虚引用
需要通过PhantomReference对象和ReferenceQueue实现:
private ReferenceQueue<OneObject> queue = new ReferenceQueue<>(); PhantomReference<OneObject> oneObjectPr = new PhantomReference<>(new OneObject(), queue);
无论是否gc,其实都获取不到通过PhantomReference创建的对象。
其仅用于管理直接内存,起到通知的作用。
这里补充一下背景。因为垃圾回收器只能管理JVM内部的内存,无法直接管理系统内存的。对于一些存放在系统内存中的数据,JVM会创建一个引用指向这部分内存。
当这个引用在回收的时候,就需要通过虚引用来管理指向的系统内存。这里还需要依赖一个队列来实现。当触发gc对一个虚引用对象回收时,会将虚引用放入创建时指定的ReferenceQueue中。之后单独对这个队列进行轮训,并做额外处理。
上demo,注意注释
/** * 虚引用 * 只用于管理直接内存,起到通知的作用 * * @author * @date 2020-05-23 */ public class ShowPhantomReference { /** * 虚引用需要的队列 */ private static final ReferenceQueue<OneObject> QUEUE = new ReferenceQueue<>(); public static void main(String[] args) { // 我们需要通过WeakReference来创建虚引用 PhantomReference<OneObject> objectPr = new PhantomReference<>(new OneObject(), QUEUE); System.out.println("虚引用objectPr的地址:" + objectPr); System.out.println("虚引用objectPr关联的oneObject对象的地址:" + objectPr.get()); // 触发gc,然后检查队列中是否有虚引用 while (true) { System.gc(); Reference<? extends OneObject> poll = QUEUE.poll(); if (poll != null) { System.out.println("队列里找到objectPr啦" + poll); break; } } } }
执行代码,可以看到以下输出:
虚引用objectPr的地址:java.lang.ref.PhantomReference@73ea3f33 虚引用objectPr关联的oneObject对象的地址:null 啊哦~OneObject被回收了 队列里找到objectPr啦java.lang.ref.PhantomReference@73ea2f33
原文链接: https://www.yukx.com/architect/article/details/2362.html 优科学习网Java强软弱虚四种引用,看完不再犯迷糊
-
分库分表大家可能听得多了,但读扩散问题大家了解吗?这里涉及到几个问题。分库分表是什么?读扩散问题是什么?分库分表为什么会引发读扩散问题?怎么解决读扩散问题?这些问题还是比较有意思的。相信兄弟们也一定有机会遇到哈哈哈。我们先从分库分表的话题聊起吧。分库分表我们平时做项目开发。一开始,通常都先用一张数据
-
目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll,I/O多路复用就是 通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。 但select,pselect,poll,epoll本质上都是
-
架构师在进行系统设计时,遵循一套复杂且综合的方法论,主要包括以下核心步骤:需求分析:理解并明确业务需求是架构设计的第一步。架构师需要与各利益相关者深入沟通,收集和分析业务需求、性能需求、安全性需求、扩展性需求等。领域建模:基于需求分析,构建抽象的业务模型或数据模型,明确系统的边界、核心实体及其关系。
-
根据阿里交易型业务的特点,以及在双十一这样业内罕有的需求推动下,我们在官方的MySQL基础上增加了非常多实用的功能、性能补丁。而在使用MySQL的过程中,数据一致性是绕不开的话题之一。本文主要从阿里巴巴“去IOE”的后时代讲起,向大家简单介绍下我们过去几年在MySQL数据一致性上的努力和实践,以及目
-
随着深度学习在图像、语言、广告点击率预估等各个领域不断发展,很多团队开始探索深度学习技术在业务层面的实践与应用。而在广告CTR预估方面,新模型也是层出不穷:WideandDeep、DeepCrossNetwork、DeepFM、xDeepFM,美团很多篇深度学习博客也做了详细的介绍。但是,当
-
1.背景搜索优化问题,是个典型的AI应用问题,而AI应用问题首先是个系统问题。经历近10年的技术积累和沉淀,美团搜索系统架构从传统检索引擎升级转变为AI搜索引擎。当前,美团搜索整体架构主要由搜索数据平台、在线检索框架及云搜平台、在线AI服务及实验平台三大体系构成。在AI服务及实验平台中,模型训练平台