Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾回收算法
文章目录
- 垃圾回收机制
- 垃圾判断算法
- 引用计数法
- 可达性分析算法
- 虚拟机栈中的引用(方法的参数、局部变量等)
- 本地方法栈中 JNI 的引用
- 类静态变量
- 运行时常量池中的常量
- 垃圾收集算法
- Mark-Sweep(标记-清除)算法
- Copying(标记-复制)算法
- Mark-and-Compact(标记-整理)算法
- Generation Collection (分代收集) 算法
垃圾回收机制
垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
垃圾判断算法
引用计数法
给对象中添加一个引用计数器:
- 每当有一个地方引用它,计数器就加 1;
- 当引用失效,计数器就减 1;
- 任何时候计数器为 0 的对象就是不可能再被使用的。
这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间循环引用的问题。
![![[Pasted image 20231011222409.png]]](https://i-blog.csdnimg.cn/direct/2ae2be8cb7c34e08b6c4e1d805135ca3.png)
可达性分析算法
该算法通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的,需要被回收。
![![[Pasted image 20231011222616.png]]](https://i-blog.csdnimg.cn/direct/044431ac269e4fc9ae7a82b892eadb84.png)
图片来源:JavaGuide
Object 6 ~ Object 10 之间虽有引用关系,但它们到 GC Roots 不可达,因此为需要被回收的对象
所谓对象之间的相互引用问题:除了对象 objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为 0,于是引用计数算法无法通知 GC 回收器回收他们。
所谓的 GC Roots,就是一组必须活跃的引用,不是对象,它们是程序运行时的起点,是一切引用链的源头。在 Java 中,GC Roots 包括以下几种:
- 虚拟机栈中的引用(方法的参数、局部变量等)
- 本地方法栈中 JNI 的引用
- 类静态变量
- 运行时常量池中的常量(String 或 Class 类型)
虚拟机栈中的引用(方法的参数、局部变量等)
public class StackReference {public void greet() {Object localVar = new Object(); // 这里的 localVar 是一个局部变量,存在于虚拟机栈中System.out.println(localVar.toString());}public static void main(String[] args) {new StackReference().greet();}
}
在 greet 方法中,localVar 是一个局部变量,存在于虚拟机栈中,可以被认为是 GC Roots。
在 greet 方法执行期间,localVar 引用的对象是活跃的,因为它是从 GC Roots 可达的。
当 greet 方法执行完毕后,localVar 的作用域结束,localVar 引用的 Object 对象不再由任何 GC Roots 引用(假设没有其他引用指向这个对象),因此它将有资格作为垃圾被回收掉。
本地方法栈中 JNI 的引用
Java 通过 JNI(Java Native Interface)提供了一种机制,允许 Java 代码调用本地代码(通常是 C 或 C++ 编写的代码)。
当调用 Java 方法时,虚拟机会创建一个栈帧并压入虚拟机栈,而当它调用本地方法时,虚拟机会通过动态链接直接调用指定的本地方法。
![![[Pasted image 20240917212049.png]]](https://i-blog.csdnimg.cn/direct/706a94cd14bb4fd28114ed2b4c7d861d.png)
JNI 引用是在 Java 本地接口(JNI)代码中创建的引用,这些引用可以指向 Java 堆中的对象。
// 假设的JNI方法
public native void nativeMethod();// 假设在C/C++中实现的本地方法
/** Class: NativeExample* Method: nativeMethod* Signature: ()V*/
JNIEXPORT void JNICALL Java_NativeExample_nativeMethod(JNIEnv *env, jobject thisObj) {jobject localRef = (*env)->NewObject(env, ...); // 在本地方法栈中创建JNI引用// localRef 引用的Java对象在本地方法执行期间是活跃的
}
在本地(C/C++)代码中,localRef 是对 Java 对象的一个 JNI 引用,它在本地方法执行期间保持 Java 对象活跃,可以被认为是 GC Roots。
一旦 JNI 方法执行完毕,除非这个引用是全局的(Global Reference),否则它指向的对象将会被作为垃圾回收掉(假设没有其他地方再引用这个对象)。
类静态变量
来看下面这段代码:
public class StaticFieldReference {private static Object staticVar = new Object(); // 类静态变量public static void main(String[] args) {System.out.println(staticVar.toString());}
}
StaticFieldReference 类中的 staticVar 引用了一个 Object 对象,这个引用存储在元空间,可以被认为是 GC Roots。
只要 StaticFieldReference 类未被卸载,staticVar 引用的对象都不会被垃圾回收。如果 StaticFieldReference 类被卸载(这通常发生在其类加载器被垃圾回收时),那么 staticVar 引用的对象也将有资格被垃圾回收(如果没有其他引用指向这个对象)。
运行时常量池中的常量
public class ConstantPoolReference {public static final String CONSTANT_STRING = "Hello, World"; // 常量,存在于运行时常量池中public static final Class<?> CONSTANT_CLASS = Object.class; // 类类型常量public static void main(String[] args) {System.out.println(CONSTANT_STRING);System.out.println(CONSTANT_CLASS.getName());}
}
在 ConstantPoolReference 中,CONSTANT_STRING 和 CONSTANT_CLASS 作为常量存储在运行时常量池。它们可以用来作为 GC Roots。
这些常量引用的对象(字符串"Hello, World"和 Object.class 类对象)在常量池中,只要包含这些常量的 ConstantPoolReference 类未被卸载,这些对象就不会被垃圾回收。
垃圾收集算法
垃圾收集算法(Garbage Collection Algorithm) 是一种自动内存管理机制,用于在程序运行时自动识别和回收不再使用的对象,以释放内存空间和提升系统性能
Mark-Sweep(标记-清除)算法
![![[Pasted image 20231011230810.png]]](https://i-blog.csdnimg.cn/direct/96b2de7317854a8c83046848290189ec.png)
图片来源:JavaGuide
标记-清除(Mark-and-Sweep)算法分为“标记(Mark)”和“清除(Sweep)”阶段:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象。
它是最基础的收集算法,后续的算法都是对其不足进行改进得到。这种垃圾收集算法会带来两个明显的问题:
- 效率问题:标记和清除两个过程效率都不高。
- 空间问题:标记清除后会产生大量不连续的内存碎片。
对于标记的对象是可回收还是不可回收对象,两种说法都有支持者,按照前者:
- 当一个对象被创建时,给一个标记位,假设为 0 (false);
- 在标记阶段,从根对象出发,将所有可达对象(或用户可以引用的对象)的标记位设置为 1 (true);
- 扫描阶段 清除标记位为 0 (false)的对象。
Copying(标记-复制)算法
![![[Pasted image 20231011231209.png]]](https://i-blog.csdnimg.cn/direct/118d8a5ee5384e239b25bb2031b56abe.png)
图片来源:JavaGuide
为了解决 标记-清除 算法的效率和内存碎片问题,复制(Copying)收集算法 将内存分为大小相同的两块,每次使用其中的一块。
当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
该算法存在的问题:
- 可用内存变小:可用内存缩小为原来的一半。
- 不适合老年代:如果存活对象数量比较大,复制性能会变得很差。
Mark-and-Compact(标记-整理)算法
![![[Pasted image 20231011231514.png]]](https://i-blog.csdnimg.cn/direct/f8b31b8188c84e50b80bf535e72105ec.png)
图片来源:JavaGuide
标记-整理(Mark-and-Compact)算法是根据老年代的特点提出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
由于多了整理这一步,因此效率不高,适合老年代这种垃圾回收频率不是很高的场景。
Generation Collection (分代收集) 算法
当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将 Java 堆分为新生代和老年代,根据各个年代的特点选择合适的垃圾收集算法,通过优化垃圾收集的效率,提高了系统的性能。
比如在新生代中,每次 GC 都会有大量对象死去,可以选择 Copying 算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。
而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。
Java 虚拟机(JVM)中的垃圾收集器通常会根据堆内存的大小、对象的存活时间等因素动态选择合适的垃圾收集算法和策略,以最大程度地提高内存利用率和应用程序的性能。
相关文章:
Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾回收算法
文章目录 垃圾回收机制垃圾判断算法引用计数法可达性分析算法虚拟机栈中的引用(方法的参数、局部变量等)本地方法栈中 JNI 的引用类静态变量运行时常量池中的常量 垃圾收集算法Mark-Sweep(标记-清除)算法Copying(标记-…...
苍穹外卖Day01-2
导入接口文档 yApi接口管理平台http://api.doc.jiyou-tech.com/ 创建项目 导入接口文件 导入结果界面 Swagger 介绍 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。 官网:ht…...
软考中级软件设计师——数据结构与算法基础学习笔记
软考中级软件设计师——数据结构与算法基本概念 什么是数据数据元素、数据项数据结构逻辑结构物理结构(存储结构) 算法什么是算法五个特性算法效率的度量时间复杂度空间复杂度 什么是数据 数据是信息的载体,是描述客观事物属性的数、字符及所…...
虚幻引擎 | (类恐鬼症)玩家和NPC语音聊天(中)
虚幻引擎 | (类恐鬼症)玩家和NPC语音聊天-CSDN博客 上篇偏重实现步骤,中篇偏重理解校准和降低延迟,下篇加入上下文背景array和设置口音 TTS通用参数 ————————————————————————————————————…...
整流电路的有源逆变工作状态
目录 1. 逆变的概念 2. 有源逆变的条件 3. 电流电路的概念 4. 产生逆变的条件 5. 三相桥式全控整流电路的有源逆变工作状态 6. 逆变角的概念 7. 逆变失败的原因 8. 最小逆变角的限制 整流电路的有源逆变状态是指通过控制整流器,使其将直流电源的能量反向送回…...
Android 签名、空包签名 、jarsigner、apksigner
jarsigner是JDK提供的针对jar包签名的通用工具, 位于JDK/bin/jarsigner.exe apksigner是Google官方提供的针对Android apk签名及验证的专用工具, 位于Android SDK/build-tools/SDK版本/apksigner.bat jarsigner: jarsigner签名空包执行的命令: jar…...
java基础(小技巧)
文章目录 一、日志输出二、字符串拼接三、日期比较四、常用注解五、Lombok的原理 提示:以下是本篇文章正文内容,下面案例可供参考 一、日志输出 之前使用的方式。在要使用的类里面定义日志类: private static Logger logger LoggerFactory…...
Android Studio 安装配置教程(Windows最详细版)
目录 前言 Android Studio 下载 Android Studio 安装 Android Studio 使用 一、创建默认项目(Compose) 二、创建常规项目 三、使用ViewBinding 四、查看Gradle版本、SDK版本、JDK版本 ① Gradle版本 ② SDK版本 ③ JDK版本 前言 Android开发…...
Cesium绘制可编辑线
Cesium 第一章 绘制可编辑线 Screen-2024-09-17-202059的副本 文章目录 Cesium一、绘制线二、编辑线三、使用 一、绘制线 1、方法 //场景相机控制viewer.scene.screenSpaceCameraController.enableRotate false; //cesium相机控制 绘制和编辑时 禁止转动场景// 鼠标样式修改…...
【算法】差分思想:强大的算法技巧
📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…...
微软开源项目 Detours 详细介绍与使用实例分享
目录 1、Detours概述 2、Detours功能特性 3、Detours工作原理 4、Detours应用场景 5、Detours兼容性 6、Detours具体使用方法 7、Detours使用实例 - 使用Detours拦截系统库中的UnhandledExceptionFilter接口,实现对程序异常的拦截 C++软件异常排查从入门到精通系列教程…...
Numba基础
1. Numba 基础 1.1 什么是 Numba? Numba 是一个 JIT 编译器,用于加速数值计算。它通过即时编译技术,将 Python 代码在运行时编译为机器代码,极大地提升执行速度,特别适合循环和矩阵操作等密集型计算。 2. Numba 基本…...
[JAVA]介绍怎样在Java中通过字节字符流实现文件读取与写入
一,初识File类及其常用方法 File类是java.io包下代表与平台无关的文件和目录,程序中操作文件和目录,都可以通过File类来完成。 通过这个File对象,可以进行一系列与文件相关的操作,比如判断文件是否存在,获…...
oracle停止当前运行的JOB或kill会话
在Oracle中,可以使用DBA_SCHEDULER_JOBS视图来查找当前正在运行的作业(job),并使用DBMS_SCHEDULER.STOP_JOB过程来停止它们 SELECT JOB_NAME, STATE FROM DBA_SCHEDULER_JOBS WHERE STATE RUNNING; SELECT * FROM DBA_SCHEDULE…...
SpringBoot 消息队列RabbitMQ 消息可靠性 数据持久化 与 LazyQueue
介绍 在默认情况下,RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟 一旦MO宕机,内存中的消息会丢失内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞 在消息队列运行的过程中…...
CLIP论文中关键信息记录
由于clip论文过长,一直无法完整的阅读该论文,故而抽取论文中的关键信息进行记录。主要记录clip是如何实现的的(提出背景、训练数据、设计模式、训练超参数、prompt的作用),clip的能力(clip的模型版本、clip…...
sshj使用代理连接服务器
之前我是用jsch连接服务器的,但是没办法使用私钥连接,搜了一下似乎是不支持新版的SSH-rsa,并且jsch很久没更新了,java - "com.jcraft.jsch.JSchException: Auth fail" with working passwords - Stack Overflow 没办法…...
【Leetcode:1184. 公交站间的距离 + 模拟】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...
VRRP 笔记
一、概念: vrrp:Virtual Router Redundancy Protocol 虚拟路由冗余协议,当网关发生故障时,进行主备切换,保证业务连续性 把多台物理机的网关虚拟成一台Virtual Router,称为 VRID VIP:虚拟IP VM…...
【洛谷】P3743 小鸟的设备 的题解
【洛谷】P3743 小鸟的设备 的题解 题目传送门 题解 水一道二分 qaq 刚开始考虑的是动态规划,但是动态规划并不能维护题目所要求的东西。所以我们将思路转向另一种求最值问题的方法:二分答案。 首先,如果一个设备在 t t t 的时间内消耗的…...
PDFMathTranslate:3步搞定学术论文AI翻译,完美保留公式排版的终极解决方案
PDFMathTranslate:3步搞定学术论文AI翻译,完美保留公式排版的终极解决方案 【免费下载链接】PDFMathTranslate PDF scientific paper translation with preserved formats - 基于 AI 完整保留排版的 PDF 文档全文双语翻译,支持 Google/DeepL/…...
食品批发厂家口碑推荐榜
在食品批发行业,选择一家口碑良好的厂家至关重要。优质的食品批发厂家不仅能提供高品质的产品,还能保障稳定的供应和良好的售后服务。今天,我们就来为大家推荐一些口碑出众的食品批发厂家,其中惠州市佳德旺食品有限公司表现尤为突…...
从GC停顿2.3s到零暂停:Java函数GraalVM Native Image迁移全周期复盘(含12个兼容性雷区)
第一章:从GC停顿2.3s到零暂停:Java函数GraalVM Native Image迁移全周期复盘(含12个兼容性雷区)在高吞吐、低延迟的Serverless函数场景中,一个Spring Boot微服务因频繁Full GC导致单次停顿高达2.3秒,严重违反…...
零克云联合创始人占冰强:如何借助OpenClaw为企业AI变革提速!
3月28日,由MoltBank&聚鲸科技、AIGCLink联合主办的“赢在OpenClaw北京站”闭门分享会,在北京成功举行。本次活动聚焦AI Agent落地、AI商业场景落地、AI法律合规边界等关键议题。在演讲环节,零克云联合创始人兼COO占冰强分享了:…...
Mars3D与Cesium结合:3DTiles数据可视化全流程解析(含示例项目)
Mars3D与Cesium结合:3DTiles数据可视化全流程解析(含示例项目) 当我们需要在Web端实现高精度的三维地理数据可视化时,3DTiles格式已经成为行业标准。而将Mars3D与Cesium这两个强大的开源GIS引擎结合使用,可以发挥出11…...
浏览器资源嗅探终极指南:如何轻松下载网页视频与音频
浏览器资源嗅探终极指南:如何轻松下载网页视频与音频 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否曾想保存网页上的精彩视频却…...
瑞芯微RK3399固件急救指南:用upgrade_tool搞定系统崩溃后的快速还原
RK3399固件灾难恢复实战:从分区表重建到全系统还原 当一块搭载RK3399的开发板因固件损坏而变砖时,那种面对黑屏的无力感,相信每个嵌入式开发者都深有体会。去年我们产线就遭遇过因批量升级失败导致30台设备集体罢工的紧急状况,正…...
我的实用设计模式之 关于Policy-based design在Windows Mobile网络连接管理的应用
Raw Data(原数据)使用不要的分析器(分析器使用不同的算法)分析出关心的Event(事件,对象,告警等等)。同时作为behavior模式之一,stragety模式也可以使用在 定义多个behavi…...
避坑指南:OpenBMI运动想象实验中的‘跨被试’与‘不跨被试’到底怎么选?
避坑指南:OpenBMI运动想象实验中的‘跨被试’与‘不跨被试’到底怎么选? 当你第一次接触OpenBMI工具箱进行运动想象(Motor Imagery, MI)实验时,最令人困惑的决策之一就是如何选择数据划分策略。是采用**跨被试…...
Qt6.10.1 + QCustomPlot 2.1.1 串口绘图实战:从Qt5老项目迁移到新版本的完整踩坑记录
Qt6.10.1与QCustomPlot 2.1.1串口绘图项目迁移实战指南 当Qt5项目需要升级到Qt6时,许多开发者都会面临兼容性挑战。特别是那些涉及串口通信和数据可视化的项目,往往隐藏着不少"坑"。本文将带你完整走一遍从Qt5老项目迁移到Qt6.10.1的全过程&am…...
