Java——》4种引用:强软弱虚

推荐链接:
    总结——》【Java】
    总结——》【Mysql】
    总结——》【Redis】
    总结——》【Kafka】
    总结——》【Spring】
    总结——》【SpringBoot】
    总结——》【MyBatis、MyBatis-Plus】
    总结——》【Linux】
    总结——》【MongoDB】
    总结——》【Elasticsearch】

引用的定义:
1.我们的数据类型必须是引用类型
2.我们这个类型的数据所存储的数据必须是另外一块内存的起始地址

image.png

一、NormalReference = 强 = 普通 = 默认

强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收

import java.io.IOException;public class T01_NormalReference {public static void main(String[] args) throws IOException {// 强引用 = 普通引用 = 默认引用,只要有一个引用指向这个对象,那么GC一定不会回收它M m = new M();// 把m设置为null,就不会再有引用引用M这个对象,也就是说把m和new M()之间的引用给打断了,不再有关联了,这时候再运行程序 ,会发现M对象被GC回收了//m = null;System.gc(); //DisableExplicitGC,显示调用GC// 要在最后阻塞当前线程,因为GC是跑在别的线程的,如果main线程直接退出了,那GC就没什么意义了// 阻塞当前线程,就是让当前整个程序不会停止System.in.read();}static class M {@Override// GC的时候,会调用 finalize()// 这里重写finalize(),只是为了观察什么时候被GC,所以这个方法永远不需要重写,而且也不应该被重写protected void finalize() throws Throwable {System.out.println("finalize");}}
}

二、SoftReference = 软

软引用在程序内存不足时,会被回收

/*** 软引用* 软引用是用来描述一些还有用但并非必须的对象。* 对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。* 如果这次回收还没有足够的内存,才会抛出内存溢出异常。** 当有一个对象,被软引用指向时,只有系统内存不够用时候,GC才会回收,内存够用GC不会回收** 软引用非常适合缓存使用** 注意:在程序运行前,设置一下堆内存最大为20M* 参数:-Xms20M -Xmx20M*/
import java.lang.ref.SoftReference;public class T02_SoftReference {public static void main(String[] args) {// 字节数组分配10M// 栈里面有个m,指向堆里的软引用SoftReference,软引用又指向了10M的字节数组SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);// m.get(),拿到字节数组,打印的是hashcode值System.out.println(m.get()); // 打印结果:[B@2344fc66System.gc();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}// 如果被回收,m.get() = null// 如果没回收,m.get() = 字节数组的hashcode值System.out.println(m.get());// 打印结果为:[B@2344fc66,虽然调用了GC,但是对象并没有被回收,因为堆内存够用//再分配一个数组15M,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉byte[] b = new byte[1024*1024*15];// 如果被回收,m.get() = null// 如果没回收,m.get() = 字节数组的hashcode值System.out.println(m.get());// 打印结果:null,因为堆空间不够用,GC把软引用给回收了}
}

三、WeakReference = 弱

弱引用就是只要JVM垃圾回收器发现了它,就会将之回收

/*** 弱引用遭到gc就会回收* 如果有一个强引用指向了这个弱引用之后,只要这个强引用消失了,这个弱引用就应该被回收,一般用在容器里,最典型的就是ThreadLocal* ThreadLocal<M> tl = new ThreadLocal<>();* tl.set(new M());** 1、哪里可以看出Entry的key是弱引用?* 往当前线程的threadLocals变量设置一个Entry,key是ThreadLocal对象,value是M对象* 由于Entry的父类是WeakReference,里面装的是ThreadLocal对象,调用了super(key),相当于new WeakReference(key),* 所以key是通过弱引用指向的ThreadLocal对象** 2、为什么Entry要使用弱引用?* 当前线程是我们的main线程,tl是强引用指向ThreadLocal对象,tl是个局部变量,方法结束它就消失了。* 如果这个ThreadLocal对象还被一个强引用的key指向的时候,那这个ThreadLocal对象就回收不了了。* 而且由于很多线程是长期存在的,这个Map就会长期存在,那这个ThreadLocal对象永远不会被消失,就可能会出现内存泄漏。** 但如果这个key是弱引用的话,就不会存在内存泄漏的问题,只要这个强引用消失了,这个弱引用就被回收了。** 3、ThreadLocal为什么会出现内存泄漏?* tl是强引用指向ThreadLocal对象,tl是个局部变量,方法结束它就消失了。* 由于key是通过弱引用指向ThreadLocal对象,这时候key的指向也被回收了,key变成了null。* 由于这个threadLocals的Map是一直存在的,但key变成null了,那value就永远访问不到了,* 如果这个Map积累的越来越多,它还是会内存泄漏,所以ThreadLocal里面的对象不用了,一定要remove掉,不然还是会有内存泄漏。*/import java.lang.ref.WeakReference;public class T03_WeakReference {public static void main(String[] args) {WeakReference<M> m = new WeakReference<>(new M());// 打印结果:com.mashibing.juc.c_022_RefTypeAndThreadLocal.T03_WeakReference$M@458ad742System.out.println(m.get());System.gc();// 打印结果:null,因为弱引用一定会被GC回收System.out.println(m.get());// tl是通过强引用指向的ThreadLocal对象ThreadLocal<M> tl = new ThreadLocal<>();// key是通过弱引用指向的ThreadLocal对象tl.set(new M());// 一定要remove,不然会发生内存泄漏tl.remove();}static class M {@Override// GC的时候,会调用 finalize()// 这里重写finalize(),只是为了观察什么时候被GC,所以这个方法永远不需要重写,而且也不应该被重写protected void finalize() throws Throwable {System.out.println("finalize");}}
}

四、PhantomReference = 虚

虚引用的回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中。注意哦,其它引用是被JVM回收后才被传入 ReferenceQueue 中的。由于这个机制,所以虚引用大多被用于引用销毁前的处理工作。还有就是,虚引用创建的时候,必须带有 ReferenceQueue

/*****     一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,*     也无法通过虚引用来获取一个对象的实例。*     为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。*     虚引用和弱引用对关联对象的回收都不会产生影响,如果只有虚引用活着弱引用关联着对象,*     那么这个对象就会被回收。它们的不同之处在于弱引用的get方法,虚引用的get方法始终返回null,*     弱引用可以使用ReferenceQueue,虚引用必须配合ReferenceQueue使用。**     jdk中直接内存的回收就用到虚引用,由于jvm自动内存管理的范围是堆内存,*     而直接内存是在堆内存之外(其实是内存映射文件,自行去理解虚拟内存空间的相关概念),*     所以直接内存的分配和回收都是有Unsafe类去操作,java在申请一块直接内存之后,*     会在堆内存分配一个对象保存这个堆外内存的引用,*     这个对象被垃圾收集器管理,一旦这个对象被回收,*     相应的用户线程会收到通知并对直接内存进行清理工作。**     事实上,虚引用有一个很重要的用途就是用来做堆外内存的释放,*     DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。**/
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;public class T04_PhantomReference {private static final List<Object> LIST = new LinkedList<>();private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();public static void main(String[] args) {PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);new Thread(() -> {while (true) {LIST.add(new byte[1024 * 1024]);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}// 打印的结果:null,虚引用是get不到值,但弱引用是可以get到值的System.out.println(phantomReference.get());}}).start();new Thread(() -> {while (true) {Reference<? extends M> poll = QUEUE.poll();if (poll != null) {System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);}}}).start();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}
}

五、四种引用的区别

1、写法

引用写法
M m = new M();
SoftReference<byte[]> m = new SoftReference<>(new byte[1024102410]);
WeakReference m = new WeakReference<>(new M());
方式一:
private static final ReferenceQueue QUEUE = new ReferenceQueue<>();
PhantomReference phantomReference = new PhantomReference<>(new M(), QUEUE);
方式二:
PhantomReference prf = new PhantomReference(new M(),new ReferenceQueue<>());

2、回收机制

引用回收机制
只要有一个引用指向这个对象,那么GC一定不会回收它
只有系统内存不够用的时候,GC才会回收这个对象,内存够用GC不会回收。
只要GC,就会回收
只要GC,就被回收,这个虚引用会装到这个队列Queue里,然后接收到一个通知,一般监听GC回收阶段,或者是回收堆外内存时使用。

3、使用场景

引用使用场景
平常中使用最多
创建缓存的时候,创建的对象放进缓存中,当内存不足时,JVM就会回收早先创建的对象。
Java源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用,一旦我不需要某个引用,JVM会自动帮我处理它,这样我就不需要做其它操作。可以解决内存泄漏的问题。
用于引用销毁前的处理工作,比如说资源释放或者回收堆外内存等。 Object.finalize() 虽然也可以做这类动作,但是这个方式即不安全又低效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/182663.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶高效预训练--降低落地成本的新思路(AD-PT)

自动驾驶高效预训练--降低落地成本的新思路 1. 之前的方法2. 主要工作——面向自动驾驶的点云预训练2.1. 数据准备 出发点&#xff1a;通过预训练的方式&#xff0c;可以利用大量无标注数据进一步提升3D检测 https://arxiv.org/pdf/2306.00612.pdf 1. 之前的方法 1.基于对比学…

手工测试1年经验面试,张口要18K,我真是服了····

由于朋友临时有事&#xff0c; 所以今天我代替朋友进行一次面试&#xff0c;他需要应聘一个测试工程师&#xff0c; 我以很认真负责的态度完成这个过程&#xff0c; 大概近30分钟。 主要是技术面试&#xff0c; 在近30分钟内&#xff0c; 我与被面试者是以交流学习的方式进行的…

未来商业趋势:无人奶柜的无限潜力

未来商业趋势&#xff1a;无人奶柜的无限潜力 随着自动售货机的普及和公共场所需求的多样化&#xff0c;无人奶柜作为一种新兴的自动售货机&#xff0c;开始出现在学校、医院、办公楼、商场等公共场所&#xff0c;为人们提供便捷、低成本的饮品购买服务。 这种无人奶柜不仅可以…

Java 高效生成按指定间隔连续递增的列表(int,double)

简介 Java 按照指定间隔生成连续递增的List 列表&#xff08;引入Stream 类和流操作来提高效率&#xff09;&#xff1a; 1. 生成递增的List< Integer> Testpublic void test009(){int start 1;int interval 2;int count 10;List<Integer> list IntStream.ite…

044_第三代软件开发-保存PDF

第三代软件开发-保存PDF 文章目录 第三代软件开发-保存PDF项目介绍保存PDF头文件源文件使用 关键字&#xff1a; Qt、 Qml、 pdf、 painter、 打印 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#xff…

10 特征向量与特征值

特征向量与特征值 什么是特征向量三维空间的旋转矩阵和线性变换特征向量二维线性变换不一定有特征向量一个特征值可能不止一个特征向量特征基 这是关于3Blue1Brown "线性代数的本质"的学习笔记。 图1 预备知识 什么是特征向量 图1 特征向量 线性变换过程中&#xff…

领跑中国APM市场,博睿数据蝉联第一!

近日&#xff0c;全球领先的IT市场研究和咨询公司IDC发布《中国IT统一运维软件产品市场跟踪报告&#xff0c;2023H1》&#xff0c;报告显示&#xff0c;博睿数据以市场份额20.14%再创新高&#xff0c;蝉联APM市场第一。 2023年上半年&#xff0c;APM市场呈现同比增长的趋势。在…

顺丰函证通API集成,无代码开发连接CRM和电商平台

1. 顺丰&#xff1a;全球第四大快递公司的无代码开发连接 顺丰是全球第四大快递公司&#xff0c;秉承 “以用户为中心&#xff0c;以需求为导向&#xff0c;以体验为根本” 的产品设计思维。顺丰不仅在国内市场深耕&#xff0c;而且横向拓展多元业务领域&#xff0c;纵深完善产…

灵魂拷问:读取 excel 测试数据真的慢吗?

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

非农数据不及预期,美元回落金价触及2000关口

上周五美国非农数据公布&#xff0c;现货黄金短线拉升近16美元&#xff0c;金价突破2000关口最高至2003.55美元/盎司&#xff0c;但随后金价转头回落&#xff0c;最终报收1992.19美元/盎司&#xff0c;涨幅收窄至0.34%。周线级别金价下跌0.61%&#xff0c;金价终止之前连续三周…

基于ssm+jsp背单词系统的设计与实现

ssm背单词系统&#xff0c;java记单词系统&#xff0c;背单词系统 运行环境&#xff1a; JAVA版本&#xff1a;JDK1.8 IDE类型&#xff1a;IDEA、Eclipse都可运行 数据库类型&#xff1a;MySql&#xff08;8.x版本都可&#xff09; 硬件环境&#xff1a;Windows 角色&#xff…

[BUUCTF NewStar 2023] week5 Crypto/pwn

最后一周几个有难度的题 Crypto last_signin 也是个板子题&#xff0c;不过有些人存的板子没到&#xff0c;所以感觉有难度&#xff0c;毕竟这板子也不是咱自己能写出来的。 给了部分p, p是1024位给了922-101位差两头。 from Crypto.Util.number import * flag b?e 655…

Java快速排序算法、三路快排(Java算法和数据结构总结笔记)[7/20]

一、什么是快速排序算法 快速排序的基本思想是选择一个基准元素&#xff08;通常选择最后一个元素&#xff09;将数组分割为两部分&#xff0c;一部分小于基准元素&#xff0c;一部分大于基准元素。 然后递归地对两部分进行排序&#xff0c;直到整个数组有序。这个过程通过 par…

私域流量搭建与运营,技巧全攻略!

2023年是比拼运营深度和服务效率的一年&#xff0c;用户对于体验的期望值将持续增长&#xff0c;企业需提供无缝的客户体验&#xff0c;以推动增长、保障收入、确保客户忠诚度。在疫情新常态下&#xff0c;企业已构建起APP、小程序等一系列线上触点矩阵&#xff0c;而各个触点之…

浅谈开口互感器在越南美的工业云系统中的应用

摘 要&#xff1a;分析低压开口式电流互感器的原理&#xff0c;结合工程实例分析开口电流互感器在低压配电系统中&#xff0c;主要是改造项目中的应用及施工细节&#xff0c;为用户快速实现智能配电提供解决方案&#xff0c;该方案具有成本低、投资少、安装接线简便等优点&…

Docker Stack部署应用详解+Tomcat项目部署详细实战

Docker Stack 部署应用 概述 单机模式下&#xff0c;可以使用 Docker Compose 来编排多个服务。Docker Swarm 只能实现对单个服务的简单部署。而Docker Stack 只需对已有的 docker-compose.yml 配置文件稍加改造就可以完成 Docker 集群环境下的多服务编排。 stack是一组共享…

MySQL -- 索引

MySQL – 索引 文章目录 MySQL -- 索引一、索引简介1.简介2.索引效率的案例 二、认识磁盘1.磁盘2.结论3.磁盘随机访问(Random Access)与连续访问(Sequential Access) 三、MySQL 与磁盘交互基本单位1.基本单位2.MySQL中的数据管理 五、索引的理解1.索引案例2.单页mysql page3.管…

库房管理软件采购申请流程代码实现解析

300rmb掏了个javavue2的小系统&#xff0c;学习代码&#xff0c;调整下申请流程。 原有的入库流程是&#xff0c;库管&#xff08;admin&#xff09;提出采购申请给采购员&#xff08;caigou&#xff09;&#xff0c;采购员采购入库时点击入库完成采购入库流程。 想弄清后端代…

figma-如何批量修改字体

一.选择字体 二.批量替换 编辑—>替换相同字体

微信小程序之自定义组件开发

1、前言 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。开发者可以将页面内的功能模块抽象成自定义组件&#xff0c;以便在不同的页面中重复使用&#xff1b;也可以将复杂的页面拆分成多个低耦…