JVM中的各类引用
JVM中的各类引用
欢迎来到我的博客:TWind的博客
我的CSDN::Thanwind-CSDN博客
我的掘金:Thanwinde 的个人主页
对象
众所不周知,Java中基本所有的对象都是分配在堆内存之中的,除开基本数据类型在栈帧中以外,其他的对象全部都分配在堆中
众所不周知,堆内存是JVM中十分重要的一个区域,以至于想尽办法的开发出更加有效率,精巧的GC来回收这一部分的空间
你new了一个引用类型的对象之后,引用会留在栈帧(类似指针),指向堆中的一块内存,其就被这个对象“占用”了
但是随着程序的运行,你new的对象会越来越多,堆内存也会越来越小,直到到一个临界值:堆内存爆了。
实际上,在你的内存不够时:(新生代爆,老年代爆等等),JVM会先通过GC来尝试回收一部分内存,然而,GC会通过可达性算法来判断这个对象应不应该被回收,而可达性算法会遍历你的GC root,对于每一个被GC root引用或间接引用的 对象,都不会被GC回收掉
那就造成了一个问题:当你想实现一些“不是很重要”的大对象,在空间不够时可以选择性的先释放掉他们来供给其他对象使用来避免堆爆掉时,就不能用常规的定义方法来定义这些方法:因为一旦你对这些对象有操作,那它大概率会变成GC root(当然实际上没有这么随意) 这就导致了,GC根本不会把他们当成垃圾来处理,但还好,Java为我们提供了一种方法来解决这个问题:更改引用类型
引用类型
Java中的引用类型可以分为:强应用,软引用,弱引用和虚引用,让我们一一解释:
强引用
强引用就像它的名字一样,是最强的引用:有点类似于化学中的共价键一样,很难断开
它普遍的存在:Object obj = new Object()便是一个典型的强引用
无论如何,一个强引用只要存在了就不会被回收,这里的“存在”指的是一个强引用直接或间接的被new出来了或是被间接的被其他强引用new出来
也就是说,基本你写代码时正常创建的对象,就全是强引用,永远不会被GC回收
那什么时候强引用对象会被回收呢?
当其除去软,虚之外的来自GC root引用都被销毁,就会被回收:最显而易见的就是引用所在的栈帧被销毁:栈帧里面的局部变量表存储着所有基本类型对象和引用类型在堆中的引用,当栈帧被销毁后,这个“引用”也会被直接销毁,这个强引用也就被断开了。这时候,还是堆中的这个对象只有这个强引用的话,他就会因为没有来自GC root的引用而被GC回收掉,但如果它拥有其他的来自GC root的强引用的话就不会被回收,但如果只拥有软引用的话那就得看空间紧不紧张了。
[!IMPORTANT]
GC root包含:
虚拟机栈引用的对象
例如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等处于存活状态的线程对象
例如Thread方法区静态属性引用的对象
例如java类的引用类型静态变量方法区常量引用的对象
例如字符串常量池的引用本地native方法jni引用的对象
Java虚拟机内部的引用
例如基本数据类型对应的class对象,一些常驻的异常对象(如NullPointerException、OutOfMemoryError),还有类加载器所有被同步锁持有的对象
反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
另外有一个显而易见的例子:
Object obj = new Object(); // 强引用 obj 指向一个新对象
obj = null; // 强引用 obj 被置为 null,对象变成不可达对象
当这个强引用obj被设成null,就会导致刚才new 的Object()就没有引用指向它了,下次GC就会把它回收掉
值得一提的是,强引用不等于GC root,就比如你有一个类:
public class objClass(){Object obj = new Object();/*...*/
}
但如果这个objClass根本就没有被用到,没有被加载,那里面的obj肯定就不能作为一个GC root了
软引用
软引用就是一个我们之前提到的:在空间不够时可以选择性的先释放掉他们来供给其他对象使用来避免堆爆掉的对象
相比起强引用,他更容易被回收:只要堆内存不够时,触发了GC,但这次GC并不会回收软引用,只有当第一次GC回收的内存仍然不够使用,进行第二次GC时才会将其回收掉
举个例子:
我们可以在虚拟机选项中加上: -Xms20m -Xmx20m -XX:+PrintGCDetails
这个选项会开启GC的输出,以及设定堆内存为20m
然后你可以运行类似于这样的代码:
static int _5MB = 1024 * 1024 * 5;public static void main(String[] args) throws IOException {List<SoftReference<byte[]>> bytesList = new ArrayList<>();for(int i = 0; i < 5; i++) {bytesList.add(new SoftReference<>(new byte[_5MB]));for(int j = 0; j <= i;j++){System.out.print(bytesList.get(j).get());}System.out.println();}}
这样你就会看到如下结果:
[B@75b84c92
[B@75b84c92[B@6bc7c054
[GC (Allocation Failure) [PSYoungGen: 1738K->480K(6144K)] 11978K->11008K(19968K), 0.0007511 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[B@75b84c92[B@6bc7c054[B@232204a1
[GC (Allocation Failure) --[PSYoungGen: 5825K->5825K(6144K)] 16353K->16417K(19968K), 0.0006529 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 5825K->5460K(6144K)] [ParOldGen: 10592K->10499K(13824K)] 16417K->15960K(19968K), [Metaspace: 3301K->3301K(1056768K)], 0.0029366 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) --[PSYoungGen: 5460K->5460K(6144K)] 15960K->15992K(19968K), 0.0005618 secs] [Times: user=0.00 sys=0.20, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 5460K->0K(6144K)] [ParOldGen: 10531K->582K(13824K)] 15992K->582K(19968K), [Metaspace: 3301K->3301K(1056768K)], 0.0038522 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
nullnullnull[B@4aa298b7
nullnullnull[B@4aa298b7[B@7d4991ad
可以看到,在内存不够时触发了GC,第一次GC都没有清理出空间,都是第二次的full GC才清理掉这些软引用(变成了null)来腾出了空间
弱引用
顾名思义,弱引用是比软引用更加弱的一种引用,有多弱呢?
对于软引用,GC不会回收,只有full GC才会将其回收
但是弱引用,GC就会将其全部回收
同样的实例程序:
static int _5MB = 1024 * 1024 * 5;public static void main(String[] args) throws IOException {List<WeakReference<byte[]>> bytesList = new ArrayList<>();for(int i = 0; i < 5; i++) {bytesList.add(new WeakReference<>(new byte[_5MB]));for(int j = 0; j <= i;j++){System.out.print(bytesList.get(j).get());}System.out.println();}}
执行结果:
[B@75b84c92
[B@75b84c92[B@6bc7c054
[GC (Allocation Failure) [PSYoungGen: 1738K->488K(6144K)] 11978K->11008K(19968K), 0.0006141 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[B@75b84c92[B@6bc7c054[B@232204a1
[GC (Allocation Failure) [PSYoungGen: 5833K->504K(6144K)] 16353K->11088K(19968K), 0.0007155 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[B@75b84c92[B@6bc7c054null[B@4aa298b7
[GC (Allocation Failure) [PSYoungGen: 5792K->504K(6144K)] 16376K->11152K(19968K), 0.0004317 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[B@75b84c92[B@6bc7c054nullnull[B@7d4991ad
HeapPSYoungGen total 6144K, used 5828K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3220,0x00000000fff00000)from space 512K, 98% used [0x00000000fff00000,0x00000000fff7e010,0x00000000fff80000)to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen total 13824K, used 10648K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)object space 13824K, 77% used [0x00000000fec00000,0x00000000ff666060,0x00000000ff980000)Metaspace used 3329K, capacity 4564K, committed 4864K, reserved 1056768Kclass space used 357K, capacity 388K, committed 512K, reserved 1048576K
可以看到,完全没有触发full GC,说明在GC阶段就已经把弱引用回收了
虚引用
虚引用是一类特殊的引用,特殊到它实际上没有引用:比起引用,它更像是一个监听器,当它指向的对象被回收时,他会被加入到引用队列中起到了一个“通知”的作用
比如如下程序:
static int _5MB = 1024 * 1024 * 5;public static void main(String[] args) throws IOException, InterruptedException {byte[] data = new byte[_5MB];ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();PhantomReference<byte[]> phantomReference = new PhantomReference<>(data, referenceQueue);List<PhantomReference<byte[]>> phantomList = new ArrayList<>();phantomList.add(phantomReference);System.out.println("Before GC: Phantom Reference = " + phantomReference.get());data = null;System.gc();Thread.sleep(1000);System.out.println("After GC: Phantom Reference = " + phantomReference.get());Reference<? extends byte[]> refFromQueue = referenceQueue.poll();if (refFromQueue != null) {System.out.println("Object has been garbage collected and added to the queue.");} else {System.out.println("Object is not yet garbage collected.");}}
结果是:
Before GC: Phantom Reference = null
After GC: Phantom Reference = null
Object has been garbage collected and added to the queue.
因为其是虚引用,所以尝试get当然获得不到对象,返回null
而当其引用的对象被GC回收后,其也被加入到了referenceQueue之中
Java的引用类型大概就是这些类容,但是这这是JVM内存管理的冰山一角,后面我会写一些文章来介绍Java最为重要的GC部分
相关文章:
JVM中的各类引用
JVM中的各类引用 欢迎来到我的博客:TWind的博客 我的CSDN::Thanwind-CSDN博客 我的掘金:Thanwinde 的个人主页 对象 众所不周知,Java中基本所有的对象都是分配在堆内存之中的,除开基本数据类型在栈帧中以外…...

thinkphp-queue队列随笔
安装 # 创建项目 composer create-project topthink/think 5.0.*# 安装队列扩展 composer require topthink/think-queue 配置 // application/extra/queue.php<?php return [connector > Redis, // Redis 驱动expire > 0, // 任务的过期时间…...

STM32标准库-TIM输出比较
文章目录 一、输出比较二、PWM2.1简介2.2输出比较通道(高级)2.3 输出比较通道(通用)2.4输出比较模式2.5 PWM基本结构1、时基单元2、输出比较单元3、输出控制(绿色右侧)4、右上波形图(以绿色脉冲…...

科技创新驱动人工智能,计算中心建设加速产业腾飞
在科技飞速发展的当下,人工智能正以前所未有的速度融入我们的生活。一辆辆无人驾驶的车辆在道路上自如地躲避车辆和行人,行驶平稳且操作熟练;刷脸支付让购物变得安全快捷,一秒即可通行。这些曾经只存在于想象中的场景,…...
figma 和蓝湖 有什么区别
以下是 Figma 和蓝湖的详细对比分析: 核心定位区别 维度Figma蓝湖本质全功能云端设计工具设计协作与交付平台核心功能设计原型协作开发交付设计稿交付标注切图协作设计能力✅ 完整矢量设计工具❌ 无设计功能(需导入其他工具文件)适用阶段全流…...
SQLServer中的存储过程与事务
一、存储过程的概念 1. 定义 存储过程(Stored Procedure)是一组预编译的 SQL 语句的集合,它们被存储在数据库中,可以通过指定存储过程的名称并执行来调用它们。存储过程可以接受输入参数、输出参数,并且可以返回执行…...

STM32H562----------ADC外设详解
1、ADC 简介 STM32H5xx 系列有 2 个 ADC,都可以独立工作,其中 ADC1 和 ADC2 还可以组成双模式(提高采样率)。每个 ADC 最多可以有 20 个复用通道。这些 ADC 外设与 AHB 总线相连。 STM32H5xx 的 ADC 模块主要有如下几个特性: 1、可配置 12 位、10 位、8 位、6 位分辨率,…...

uniapp 安卓 APP 后台持续运行(保活)的尝试办法
在移动应用开发领域,安卓系统的后台管理机制较为复杂,应用在后台容易被系统回收,导致无法持续运行。对于使用 Uniapp 开发的安卓 APP 来说,实现后台持续运行(保活)是很多开发者面临的重要需求,比…...

AI大数据模型如何与thingsboard物联网结合
一、 AI大数据与ThingsBoard物联网的结合可以从以下几个方面实现: 1. 数据采集与集成 设备接入:ThingsBoard支持多种通信协议(如MQTT、CoAP、HTTP、Modbus、OPC-UA等),可以方便地接入各种物联网设备。通过这些协议&am…...

【SSM】SpringBoot笔记2:整合Junit、MyBatis
前言: 文章是系列学习笔记第9篇。基于黑马程序员课程完成,是笔者的学习笔记与心得总结,供自己和他人参考。笔记大部分是对黑马视频的归纳,少部分自己的理解,微量ai解释的内容(ai部分会标出)。 …...
STM32——CAN总线
STM32——CAN总线 1. CAN总线基础概念 1.1 CAN总线简介 控制器局域网(Controller Area Network, CAN)是由Bosch公司开发的串行通信协议,专为汽车电子和工业控制设计,具有以下核心特性: 多主控制架构:所有…...

嵌入式面试高频!!!C语言(四)(嵌入式八股文,嵌入式面经)
更多嵌入式面试文章见下面连接,会不断更新哦!!关注一下谢谢!!!! https://blog.csdn.net/qq_61574541/category_12976911.html?fromshareblogcolumn&sharetypeblogcolumn&…...
数据治理在制造业的实践案例
一、数据治理在制造业的重要性 随着工业4.0的到来,制造业正经历着前所未有的变革。数据治理作为制造业数字化转型的关键组成部分,对提升企业竞争力、优化生产流程、提高产品质量和客户满意度等方面起着至关重要的作用。在制造业中,数据治理不仅涉及到数据的收集、存…...
【强化学习】——03 Model-Free RL之基于价值的强化学习
【强化学习】——03 Model-Free RL之基于价值的强化学习 \quad\quad \quad\quad 动态规划算法是基于模型的算法,要求已知状态转移概率和奖励函数。但很多实际问题中环境 可能是未知的,这就需要不基于模型(Model-Free)的RL方法。 \quad\quad 其又分为: 基于价值(Valu…...

Edge(Bing)自动领积分脚本部署——基于python和Selenium(附源码)
微软的 Microsoft Rewards 计划可以通过 Bing 搜索赚取积分,积分可以兑换礼品卡、游戏等。每天的搜索任务不多,我们可以用脚本自动完成,提高效率,解放双手。 本文将手把手教你如何部署一个自动刷积分脚本,并解释其背…...
html表格转换为markdown
文章目录 工具功能亮点1.核心实现解析1. 剪贴板交互2. HTML检测与提取3. 转换规则设计 2. 完整代码 在日常工作中,我们经常遇到需要将网页表格快速转换为Markdown格式的场景。无论是文档编写、知识整理还是数据迁移,手动转换既耗时又容易出错。本文将介绍…...

VsCode 安装 Cline 插件并使用免费模型(例如 DeepSeek)
当前时间为 25/6/3,Cline 版本为 3.17.8 点击侧边栏的“扩展”图标 在搜索框中输入“Cline” 找到 Cline 插件,然后点击“安装” 安装完成后,Cline 图标会出现在 VS Code 的侧边栏中 点击 Use your own API key API Provider 选择 OpenRouter…...

短视频矩阵系统源码新发布技术方案有那几种?
短视频矩阵运营在平台政策频繁更迭的浪潮中,已成为内容分发的核心战场。行业领先者如筷子科技、云罗抖去推、超级编导等平台,其稳定高效的代发能力背后,离不开前沿技术方案的强力支撑。本文将深入剖析当前主流的六大短视频矩阵系统代发解决方…...

React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例
前言 useResolvedPath 是 React Router v6 提供的一个实用钩子,用于解析给定路径为完整路径对象。 它根据当前路由上下文解析相对路径,生成包含 pathname、search 和 hash 的完整路径对象。 一、useResolvedPath 核心用途 路径解析:将相对…...
【PmHub面试篇】性能监控与分布式追踪利器Skywalking面试专题分析
你好,欢迎来到本次关于PmHub整合性能监控与分布式追踪利器Skywalking的面试系列分享。在这篇文章中,我们将深入探讨这一技术领域的相关面试题预测。若想对相关内容有更透彻的理解,强烈推荐参考之前发布的博文:【PmHub后端篇】Skyw…...

Cursor快速梳理ipynb文件Prompt
1. 整体鸟瞰 请在不运行代码的前提下,总结 <文件名.ipynb> 的主要目的、核心逻辑流程和输出结果。阅读整个项目目录,列出每个 .ipynb / .py 文件的角色,以及它们之间的数据依赖关系(输入→处理→输出)。2. 结构…...

天机学堂-分页查询
需求 分页查询我的课表 返回: 总条数、总页数、当前页的课表信息的集合 返回的VO(已经封装成统一的LearningLessonsVO) 定义Controller RestController RequestMapping("/lessons") RequiredArgsConstructor public class Lear…...
业态即战场:零售平台的生意模型与系统设计解构
目录 一、当我们在电商买菜、点外卖时,其实是零售业态在进化 (一)从“商场选货”到“算法推货”:零售的时代已经不同 (二)“控货”和“卖场”——零售的两种基本商业模式 二、四种经典零售业态解析:控货 vs 卖场,地面 vs 线上 (一)地面控货零售:直营模式的黄金…...

微算法科技(NASDAQ:MLGO)基于信任的集成共识和灰狼优化(GWO)算法,搭建高信任水平的区块链网络
随着数字化转型的加速,区块链技术作为去中心化、透明且不可篡改的数据存储与交换平台,正逐步渗透到金融、供应链管理、物联网等多个领域,探索基于信任的集成共识机制,并结合先进的优化算法来提升区块链网络的信任水平,…...

全新Xsens Animate版本是迄今为止最大的软件升级,提供更清晰的数据、快捷的工作流程以及从录制开始就更直观的体验
我们整合了专业人士喜爱的 Xsens 动捕功能,并使其更加完善。全新Xsens Animate版本是我们迄今为止最大的软件升级,旨在提供更清晰的数据、更快捷的工作流程以及从录制开始就更直观的体验。 从制作游戏动画到流媒体直播头像或构建实时电影内容࿰…...

大语言模型评测体系全解析(下篇):工具链、学术前沿与实战策略
文章目录 一、评测工具链:从手工测试到自动化工程的效率革命(一)OpenCompass:开源评测框架的生态构建1. 技术架构:三层架构实现评测自动化2. 开发者赋能:从入门到进阶的工具矩阵 (二)…...

python打卡day46@浙大疏锦行
知识点回顾: 不同CNN层的特征图:不同通道的特征图什么是注意力:注意力家族,类似于动物园,都是不同的模块,好不好试了才知道。通道注意力:模型的定义和插入的位置通道注意力后的特征图和热力图 内…...
C++.OpenGL (1/64) 创建窗口(Hello Window)
OpenGL 创建窗口(Hello Window) 步骤详解与代码实现 #mermaid-svg-436DlGvysFQogISc {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-436DlGvysFQogISc .error-icon{fill:#552222;}#mermaid-svg-436DlGvysFQogISc…...

Excel 发现此工作表中有一处或多处公式引用错误。请检查公式中的单元格引用、区域名称、已定义名称以及到其他工作簿的链接是否均正确无误。弹窗
Excel 提示“发现此工作表中有一处或多处公式引用错误”通常表示公式中存在无效引用。以下是系统化的检查步骤,帮助你定位和修复问题: 1. 检查单元格引用: 无效单元格引用:检查公式中的单元格地址(如 A1、B10&…...

NVIDIA DRIVE AGX平台:引领智能驾驶安全新时代
随着科技的不断进步,汽车行业正迎来前所未有的变革,智能驾驶技术成为全球产业竞相布局的焦点之一。然而,这场技术革命的背后,最关键且被广泛关注的是安全性问题。近日,我认真研读了NVIDIA发布的《自动驾驶安全报告》白…...