【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法
图解 JVM 垃圾回收(一)
- 1.前言
- 1.1 什么是垃圾
- 1.2 内存溢出和内存泄漏
- 2.垃圾回收的定义与重要性
- 3.GC 判断策略
- 3.1 引用计数算法
- 3.2 可达性分析算法
- 4.引用类型
- 5.垃圾回收算法
- 5.1 标记-复制(Copying)
- 5.2 标记-清除(Mark-Sweep)
- 5.3 标记-整理(Mark-Compact)
- 5.4 分代收集理论
- 5.5 垃圾回收阶段算法小结
1.前言
1.1 什么是垃圾
垃圾 是指运行程序中 没有任何引用指向的对象,需要被回收。
1.2 内存溢出和内存泄漏
内存溢出:经过垃圾回收之后,内存仍旧无法存储新创建的对象,内存不够溢出。
内存泄漏:又叫 “存储泄漏”,对象不会再被程序使用了,但是 GC 又不能回收它们。例如:IO 流不适用了但是没有被 Close、数据库连接 JDBC 没有被 Close。这些对象不会被回收就会占据内存,大量的此类对象存在,也是导致内存溢出的原因。
2.垃圾回收的定义与重要性
垃圾回收(Garbage Collection
,简称 GC
)是内存管理的核心组成部分,它负责自动回收不再使用的内存空间。在 Java 中,程序员不需要手动释放对象占用的内存,一旦对象不再被引用,垃圾回收器就会在适当的时机回收它们所占用的内存。这样可以避免 内存泄漏 和 野指针,从而大大减轻了程序员的负担,也使得 Java 成为一个相对安全、易于开发的编程语言。
- 防止内存泄漏:手动管理内存容易导致内存泄漏,而 GC 可以自动回收不再使用的对象,防止内存泄漏的发生。
- 提高开发效率:程序员不再需要关心内存释放的问题,可以更加集中精力在业务逻辑的实现上。
- 系统性能和稳定性:通过有效的垃圾回收策略,可以保证系统的性能和稳定性。
垃圾回收的基本步骤分两步:
- 1️⃣ 查找内存中不再使用的对象(GC 判断策略)
- 2️⃣ 释放这些对象占用的内存(GC 收集算法)
3.GC 判断策略
3.1 引用计数算法
给对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收。正因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法。
public class ReferenceCountingGC {public Object instance = null;public static void main(String[] args) {ReferenceCountingGC objectA = new ReferenceCountingGC();ReferenceCountingGC objectB = new ReferenceCountingGC();objectA.instance = objectB;objectB.instance = objectA;}
}
3.2 可达性分析算法
通过 GC Roots
作为起始点进行搜索,能够到达到的对象都是存活的,不可达的对象可被回收。
哪些对象可以作为 GC Roots
呢?
- 虚拟机栈(栈帧中的局部变量表)中引用的对象
- 本地方法栈(Native 方法)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 所有被同步锁持有的对象
JNI
(Java Native Interface
)引用的对象
public void method() { Object localVariable = new Object(); // localVariable 是 GC Roots
}public class MyClass { private static Object staticObject = new Object(); // staticObject 是 GC Roots
}public class MyClass { private static final String CONSTANT_STRING = "constant"; // CONSTANT_STRING 是 GC Roots
}public synchronized void synchronizedMethod() { // 当前对象(this)在执行同步方法时是 GC Roots
}
4.引用类型
无论是通过引用计算算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关。
Java 中有四种类型的引用,它们对垃圾回收的影响不同:
- 强引用(
Strong Reference
):最常见的引用类型,只要对象有强引用指向,它就不会被垃圾回收。 - 软引用(
Soft Reference
):软引用可以帮助垃圾回收器回收内存,只有在内存不足时,软引用指向的对象才会被回收。 - 弱引用(
Weak Reference
):弱引用指向的对象在下一次垃圾回收时会被回收,不管内存是否足够。 - 虚引用(
Phantom Reference
):虚引用的主要用途是跟踪对象被垃圾回收的状态,虚引用指向的对象总是可以被垃圾回收。
import java.lang.ref.*;public class ReferenceTypes {public static void main(String[] args) {Object strongRef = new Object(); // 强引用SoftReference<Object> softRef = new SoftReference<>(new Object()); // 软引用WeakReference<Object> weakRef = new WeakReference<>(new Object()); // 弱引用PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), new ReferenceQueue<>()); // 虚引用System.gc(); // 触发垃圾回收System.out.println("Strong Reference: " + strongRef);System.out.println("Soft Reference: " + softRef.get());System.out.println("Weak Reference: " + weakRef.get());System.out.println("Phantom Reference: " + phantomRef.get());}
}
5.垃圾回收算法
5.1 标记-复制(Copying)
它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
- ✅ 优点: 减少内存碎片,提高空间利用率。
- ⭕ 缺点: 减半了可用的堆内存,可能增加垃圾回收的频率。
5.2 标记-清除(Mark-Sweep)
算法分为“标记”和“清除”阶段:
标记清除算法分为两个主要步骤:标记 和 清除。
- 标记阶段: 在标记阶段,垃圾回收器会从
GC Roots
开始,遍历所有可达的对象,并标记它们为活动对象。 - 清除阶段: 在清除阶段,垃圾回收器会遍历整个堆,回收所有未被标记的对象的内存。
有两个明显的问题:
- 效率问题:如果需要标记的对象太多,效率不高。
- 空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致在运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集。
5.3 标记-整理(Mark-Compact)
标记整理算法是标记清除算法的改进版本。它在标记和清除的基础上增加了整理阶段,将所有活动对象向一端移动,从而消除内存碎片。
- ✅ 优点: 解决了内存碎片化问题,提高了空间利用率。
- ⭕ 缺点: 移动对象增加了额外的开销。
5.4 分代收集理论
当前虚拟机的垃圾收集都采用分代收集算法,根据对象存活周期的不同将内存分为几块。一般将 Java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
- 新生代(
Young Generation
):使用复制算法,因为新生代中的对象生命周期较短。 - 老年代(
Tenured Generation
):使用标记整理或标记清除算法,因为老年代中的对象生命周期较长,且数量较少。
1️⃣ 新生代的回收算法(以 复制 算法为主)
- 所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。
- 新生代内存按照 8 : 1 : 1 8:1:1 8:1:1 的比例分为一个
eden
区和两个survivor
(survivor0
,survivor1
)区(一般而言)。大部分对象在eden
区中生成。回收时先将eden
区存活对象复制到一个survivor0
区,然后清空eden
区,当这个survivor0
区也存放满了时,则将eden
区和survivor0
区存活对象复制到另一个survivor1
区,然后清空eden
和这个survivor0
区,此时survivor0
区是空的,然后将survivor0
区和survivor1
区交换,即保持survivor1
区为空, 如此往复。 - 当
survivor1
区不足以存放eden
和survivor0
的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC
(Major GC
),也就是新生代、老年代都进行回收。 - 新生代发生的 GC 也叫做
Minor GC
,Minor GC
发生频率比较高(不一定等eden
区满了才触发)。
2️⃣ 老年代的回收算法(以 标记-清除、标记-整理 为主)
- 在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到老年代中。因此,可以认为老年代中存放的都是一些生命周期较长的对象。
- 内存比新生代也大很多(大概比例是 1 : 2 1:2 1:2),当老年代内存满时触发
Major GC
,Major GC
发生频率比较低,老年代对象存活时间比较长,存活率标记高。
3️⃣ 永久代(Permanet Generation
)的回收算法
JDK 1.8 及以后方法区的实现变成了元空间。
用于存放静态文件,如Java类、方法等。永久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class,例如 Hibernate 等,在这种时候需要设置一个比较大的永久代空间来存放这些运行过程中新增的类。永久代也称 方法区。方法区主要回收的内容有:废弃常量和无用的类。对于废弃常量也可通过根搜索算法来判断,但是对于无用的类则需要同时满足下面 3 个条件:
- 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
- 加载该类的 ClassLoader 已经被回收。
- 该类对应的
java.lang.Class
对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
5.5 垃圾回收阶段算法小结
标记复制 | 标记清除 | 标记压缩 | |
---|---|---|---|
速率 | 最快 | 中 | 最慢 |
空间开销 | 两个大小相同的空间 | 少(会堆积碎片) | 少(不会碎片堆积) |
移动对象 | 是 | 否 | 是 |
相关文章:

【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法
图解 JVM 垃圾回收(一) 1.前言1.1 什么是垃圾1.2 内存溢出和内存泄漏 2.垃圾回收的定义与重要性3.GC 判断策略3.1 引用计数算法3.2 可达性分析算法 4.引用类型5.垃圾回收算法5.1 标记-复制(Copying)5.2 标记-清除(Mark…...
做抖店需要注意的几大点,新手最易踩坑,都给你们总结到这了!
我是电商珠珠 抖店的运营流程很简单,选品上架、获取流量(找达人、自播、投千川等)、出单发货、做体验分等。出新手期就会有体验分,体验分就是店铺的权重,体验分越高店铺的权重也就越大。 但是作为新手的话࿰…...
小程序API能力汇总——基础容器API(三)
ty.getAccountInfo 获取小程序账号信息 需引入MiniKit,且在>3.1.0版本才可使用 参数 Object object 属性类型默认值必填说明completefunction否接口调用结束的回调函数(调用成功、失败都会执行)successfunction否接口调用成功的回调函数…...
处理目标检测中的类别不均衡问题
目标检测中,数据集中类别不均衡是一个常见的问题,其中一些类别的样本数量明显多于其他类别。这可能导致模型在训练和预测过程中对频繁出现的类别偏向,而忽略掉罕见的类别。本文将介绍如何处理目标检测中的类别不均衡问题,以提高模…...

(03)Hive的相关概念——分区表、分桶表
目录 一、Hive分区表 1.1 分区表的概念 1.2 分区表的创建 1.3 分区表数据加载及查询 1.3.1 静态分区 1.3.2 动态分区 1.4 分区表的本质及使用 1.5 分区表的注意事项 1.6 多重分区表 二、Hive分桶表 2.1 分桶表的概念 2.2 分桶表的创建 2.3 分桶表的数据加载 2.4 …...
2024年首发!高级界面控件Kendo UI全新发布2024 Q1
Kendo UI是带有jQuery、Angular、React和Vue库的JavaScript UI组件的最终集合,无论选择哪种JavaScript框架,都可以快速构建高性能响应式Web应用程序。通过可自定义的UI组件,Kendo UI可以创建数据丰富的桌面、平板和移动Web应用程序。通过响应…...

stable diffusion webui学习总结(2):技巧汇总
一、脸部修复:解决在低分辨率下,脸部生成异常的问题 勾选ADetailer,会在生成图片后,用更高的分辨率,对于脸部重新生成一遍 二、高清放大:低分辨率照片提升到高分辨率,并丰富内容细节 1、先通过…...

java 培训班预定管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目
一、源码特点 java 培训班预定管理系统是一套完善的java web信息管理系统 采用serlvetdaobean,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发…...
Python内置函数06——join
文章目录 概述语法实例展示注意事项 概述 Python内置函数join()用于将序列中的元素连接成一个字符串。 语法 str.join(iterable) 参数:iterable——一个可迭代对象中元素连接而成,元素之间用str分隔。 实例展示 eg1:用join()连接列表中…...
linux安装单机版redis详细步骤,及python连接redis案例
文章目录 linux相关工具yum方式安装redis使用编译安装redis配置redis为systemctl启动其它: 安装redis6.0python连接redis案例 linux相关工具 ./redis-benchmark #用于进行redis性能测试的工具 ./redis-check-dump #用于修复出问题的dump.rdb文件 ./redis-cli …...
ts总结大全
ts类型 TS类型除了原始js类型之外,还增加类型,例如:枚举、接口、泛型、字面量、自定义、类型断言、any、类型声明文件 数组类型两种写法:类型 [] 或 Array <类型> let arr:number[][1,2,3,4] let arr:string[][a] let arr…...
前端登录随机数字字母组合验证
背景:系统登录页面只有用户名密码一种校验方式,没有验证码,可能导致暴力破解。 实现逻辑: <el-form-item prop="code"><el-inputv-model="loginForm.captchaCode"auto-complete="off"placeholder="验证码"style="wi…...

基于Java+SpringBoot+vue+elementui 实现即时通讯管理系统
目录 系统简介效果图源码结构试用地址源码下载地址技术交流 博主介绍: 计算机科班人,全栈工程师,掌握C、C#、Java、Python、Android等主流编程语言,同时也熟练掌握mysql、oracle、sqlserver等主流数据库,能够为大家提供…...
代码随想录算法训练营第50天(动态规划07 ● 70. 爬楼梯 (进阶) ● 322. 零钱兑换 ● 279.完全平方数
动态规划part07 70. 爬楼梯 (进阶)解题思路总结 322. 零钱兑换解题思路总结 279.完全平方数解题思路 70. 爬楼梯 (进阶) 这道题目 爬楼梯之前我们做过,这次再用完全背包的思路来分析一遍 文章讲解: 70. 爬…...

【软考问题】-- 13 - 知识精讲 - 项目绩效域管理
一、基本问题 问题1:干系人绩效域的预期目标主要包含什么? ①与干系人建立高效的工作关系;②干系人认同项目目标;③支持项目的干系人提高了满意度,并从中收益;④反对项目的干系人没有对项目产生负面影响。问…...

VSCode无法连接远程服务器的两种解决方法
文章目录 VSCode Terminal 报错解决方式1解决方式2you are connected to an OS version that is unsupported by Visual Studio Code解决方法 VSCode Terminal 报错 直接在terminal或cmd中使用ssh命令可以连接服务器,但是在vscode中存在报错,最后一行为…...

【Kuiperinfer】笔记01 项目预览与环境配置
学习目标 实现一个深度学习推理框架设计、编写一个计算图实现常见的算子,例如卷积、池化、全连接学会如何进行算子的优化加速使用自己的推理框架推理常见模型,检查结果是否能够和torch对齐 什么是推理框架? 推理框架用于对已经训练完成的模…...

都2024了,你还在使用websocket实现实时消息推送吗?
前言 在日常的开发中,我们经常能碰见服务端需要主动推送给客户端数据的业务场景,比如数据大屏的实时数据,比如消息中心的未读消息,比如聊天功能等等。 本文主要介绍SSE的使用场景和如何使用SSE。 服务端向客户端推送数据的实现…...
javaScript实现客户端直连华为云OBS实现文件上传、断点续传、断网重传
写在前面:在做这个调研时我遇到的需求是前端直接对接华为云平台实现文件上传功能。上传视频文件通常十几个G、客户工作环境网络较差KB/s,且保证上传是稳定的,支持网络异常断点重试、文件断开支持二次拖入自动重传等。综合考虑使用的华为云的分…...

微信小程序:实现微信小程序应用首页开发 (本地生活首页)
文章目录 小程序应用页面开发1、创建项目并配置项目目录结构配置导航栏效果三、配置 tabBar 效果四、轮播图实现4.1 创建轮播图数据容器4.2 定义一个请求轮播图数据的接口4.3 页面加载调用 数据请求接口 五、九宫格实现5.1 获取九宫格数据5.2 结构和样式的完善六、图片布局实现…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...