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.hqwc.cn/news/163906.html

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

相关文章

微服务项目,请求从发出到后端处理器的历程

点击登录按钮,发出 http://localhost:8803/service_6001/admin/login/in请求,这是一个由nginx配置的前端项目 查看配置文件,该条请求会被映射形成对http://localhost:51603/admin/login/in的post请求 upstream heima-admin-gateway {server localhost:51603; } server {liste…

Apple :苹果将在明年年底推出自己的 AI,预计将随 iOS 18 一起推出

本心、输入输出、结果 文章目录 Apple &#xff1a;苹果将在明年年底推出自己的 AI&#xff0c;预计将随 iOS 18 一起推出前言三星声称库克相关图片弘扬爱国精神 Apple &#xff1a;苹果将在明年年底推出自己的 AI&#xff0c;预计将随 iOS 18 一起推出 编辑&#xff1a;简简单…

技术分享 | 想做App测试就一定要了解的App结构

app 的结构包含了 APK 结构和 app 页面结构两个部分 APK结构 APK 是 Android Package 的缩写&#xff0c;其实就是 Android 的安装包。通过将 APK 文件直接传到 Android 模拟器或 Android 手机中执行即可安装。 APK 文件其实是 zip 格式&#xff0c;但后缀名被修改为 apk&am…

iPortal如何灵活设置用户名及密码的安全规则

作者&#xff1a;yx 目录 前言 一、配置文件介绍 1、<passwordRules>节点 注意事项&#xff1a; 2、<usernameRules>节点 二、应用实例 1、配置文件设置 2、验证扩展结果 三、结果展示 前言 SuperMap iPortal提供了扩展账户信息合规度校验规则的能力&#…

xilinx primitives(原语)

Xilinx的原语分为10类&#xff0c;包括&#xff1a;计算组件&#xff0c;IO端口组件&#xff0c;寄存器/锁存器&#xff0c;时钟组件&#xff0c;处理器组件&#xff0c;移位寄存器&#xff0c;配置和检测组件&#xff0c;RAM/ROM组件&#xff0c;Slice/CLB组件&#xff0c;G-t…

SCI论文投稿经验分享,建议收藏!

对医药学专业的学生而言&#xff0c;让自己的医学论文在SCI期刊发表关乎评优、申学&#xff0c;十分重要。笔者根据多位常笑医学网用户的SCI论文投稿经历&#xff0c;汇总了一些SCI论文投稿经验与大家分享。 投稿前的准备工作很必要 用好查刊选刊工具效率翻倍 首先&#xff0c…

Markdown写作应用推荐

MWeb Pro 是一款适用于macOS的专业Markdown写作、笔记本应用软件。喜欢写博客的朋友&#xff0c;那你一定会需要 MWeb Pro 这款软件。为您提供最佳的写作体验。 Markdown 语法支持&#xff1a; 使用 Github Flavored Markdown 语法&#xff0c;简称 GFM 语法。支持表格、TOC、…

【C++】多态 ⑬ ( 多继承中应用 “ 抽象类 “ | 接口和抽象类 | C++ 语言中接口实现 | 只定义 纯虚函数 的 抽象类作接口 | )

文章目录 一、多继承中应用 " 抽象类 "1、接口和抽象类2、编程语言对接口和多继承的支持3、C 语言中接口实现 二、代码示例 - 多继承中应用 " 抽象类 " 一、多继承中应用 " 抽象类 " 1、接口和抽象类 接口 Interface 和 抽象类 AbstractClass 都…

【owt】p2p client mfc 工程梳理

1年前构建的,已经搞不清楚了。所以梳理下,争取能用较新的webrtc版本做测试。最早肯定用这个测试跑通过 【owt】p2p Signaling Server 运行、与OWT-P2P-MFC 交互过程及信令分析官方的mfc客户端 估计是构造了多个不同的webrc版本的客户端

NtripShare Caster高精度定位CORS服务软件

NtripShare CORS是NtripShare GNSS系列软件中最早的软件系统&#xff0c;也是NtripShare名称的起源。 所谓GNSS CORS服务系统一般构成&#xff1a; 1&#xff09;基准站网&#xff1a;由若干个分布合理的GNSS 基准站组成&#xff1b; 2&#xff09;数据传输系统&#xff1a;…

服务号怎么改成订阅号

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;在推送频率上来看&#xff0c;服务号每月能推送四条消息&#xff0c;而订阅号可以每天&#xff08;24小时&#xff09;推送一条消息。如果企业开通公众号的目的是提供服务&#xff0c;例如售前资讯…

计算机基础知识45

JS的RegExp对象(正则) text: 正则校验数据 # T/F match: 匹配 # (3) [s, s, s] //定义 var reg1 new RegExp("^[a-zA-Z][a-zA-Z0-9]{5,11}"); var reg2 /^[a-zA-Z][a-zA-Z0-9]{5,9}$/; //正则校验数据 var res reg1.test(jason666); console.log(res…