Java 垃圾回收
文章目录
- 1 Java 垃圾回收
- 1.1 JVM
- 1.2 Java 对象生命周期
- 2 如何判断一个对象可被回收
- 2.1 引用计数算法
- 2.2 可达性分析算法
- 3 垃圾回收过程
- 3.1 总体过程
- 3.2 为什么要进行世代垃圾回收?
- 3.3 分代垃圾回收过程
在 C 和 C++ 中,许多对象要求程序员声明他们后为其分配资源,然后才能安全地使用对象。使用完后,则需要程序员将这些资源释放到自由内存池。如果资源得不到释放,则认为代码泄露内存。然而,如果过早地释放,又可能发生数据丢失、Null指针等问题。
Java 和 C# 都有单独的管理应用程序管理对象的生存期并进行垃圾回收 (Garbage Collection - GC
) ,这样程序员可以不再关心内存释放问题,保证系统的性能和稳定性。
这里记录 Java 垃圾回收相关知识点,后面会再记录 C# 垃圾回收。
部分借鉴网络一些总结文章
1 Java 垃圾回收
Java 中,JVM
通过跟踪已经分配资源的引用来释放不再使用的堆存。只要 JVM
检测到对象不再被引用,垃圾回收器就会在适当的时候回收对象。
1.1 JVM
下载 Java 的时候,我们会得到 JRE (Java Runtime Environment)
,JRE 中包括了 JVM (Java Virtual Machine)
和 类库 (Java platform core classes
, Java platform libraries
)。
Java 语言的一个重要特点就是与平台无关,即得益于 JVM
的引入,Java在不同平台上运行时不需要重新编译,秩序生成在 JVM
上运行的目标代码,就可以多平台运行。
JVM
定义了程序执行期间是用的数据区域,如程序计数器、堆、栈、方法区、运行时常量池等。这些数据区域中的一些在JVM启动时创建,JVM退出时销毁。
1.2 Java 对象生命周期
Java 中,对象的生命周期包括:
public class ObjectLifecycle {public static void main(String[] args) {ObjectLifecycle obj = new ObjectLifecycle(); // 创建阶段// 使用阶段obj = null; // 不可达阶段System.gc(); // 触发垃圾回收,进入回收阶段}@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("垃圾回收前调用finalize方法");}
}
2 如何判断一个对象可被回收
2.1 引用计数算法
给对象添加一个引用计数器,对象每增加一个引用,计数器加1,引用失效计数器减1,引用计数为0的对象可以被回收。
假如两个对象互相引用,那么引用计数器永远不会为0,导致对象无法回收,因此 JVM 不再使用引用计数算法:
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;}
}
2.2 可达性分析算法
通过 GC Roots 作为起始点进行搜索,所有不可达的对象即为可被回收的对象。
Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC Roots 一般包含以下内容:
在虚拟机栈(栈帧中的本地变量表)中引用的对象:
Java public void method() { Object localVariable = new Object(); // localVariable是GC Roots }
在方法区中类静态属性引用的对象:
Java public class MyClass { private static Object staticObject = new Object(); // staticObject是GC Roots }
在方法区中常量引用的对象:
Java public class MyClass { private static final String CONSTANT_STRING = “constant”; // CONSTANT_STRING是GC Roots }
在本地方法栈中JNI(即通常所说的Native方法)引用的对象:
Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
所有被同步锁(synchronized关键字)持有的对象:
Javapublic synchronized void synchronizedMethod() { // 当前对象(this)在执行同步方法时是GC Roots }
所有被同步锁(synchronized关键字)持有的对象:
3 垃圾回收过程
3.1 总体过程
Step1. 标记 (Marking)
GC 在这个阶段辨别内存是否被使用,被引用的对象这里展示为蓝色,没有被引用的为橙色。这个过程效率不高
Step2: 标准清理 (Normal Deletion)
清理时,直接把可以回收的对象内存释放,留下被引用的对象和指向可用空间的指针。内存碎片会导致没有足够连续的空间给大对象分配内存
Step3: 压缩清理 (Deletion with Compacting)
通过把被引用的对象都移动到一起,后续为新对象分配内存则会更加容易和快速。
3.2 为什么要进行世代垃圾回收?
如上所述,标记和压缩 JVM
中所有对象是相当低效的,随着分配的对象越来越多,对象表越来越到,导致垃圾回收时间越来越长。同时,又有大量实证表明,大多数对象生命都是短暂的。
下面是数据示例图,Y周显示分配的字节数存活时间,X是随着时间推移分配的字节数。
即随着时间推移,分配的对象越来越少对。
因此,从对象分配的行为中,为了提高JVM
性能,堆被分为了更小的部分(或成为代),分别是:新生代(Young Gneration)、老年代 (Old Generation) 和 永久代(Permanent Generation).
新生代:新对象首先被分配到这里,当年轻代内存用尽,会触发一次 minor garbage colletion
。如果对象的死亡率高,那么这次 minor garbage collection
则会有效的优化内存。新生代会被分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用一块 Eden 和一块 Survivor。回收时,会将 Eden 和 Survivor 中还存活得对象复制到另一块 Survivor空间中,最后清理 Eden 和使用过的那一块 Survivor。
这个过程会快速地完成,当另一块 Survivor不足以存放 Eden 和 Survivor 存活对象时,所有幸存对象 (surviving objects) 会被标记年龄并移动到 old generation
。
Minor GC - Stop the world Event:Minor GC
是 Stop the world
的行为,即所有的应用县城都要停止,直到整个操作完成。
老年代: 一般来说,新生代对象的age达到一定的阈值,就会被移动到老年代,而老年代的回收称为 major garbage collection
。
Major GC - Stop the world Event: Major GC
也是 Stop the world
的行为,通常会更慢一些,所以对于响应式应用程序,应该尽量减少这类GC,由于 Java 虚拟机提供了多种垃圾回收器,这个GC的长度受垃圾回收器所影响。
永久代: 这里面包括了 JVM
描述应用进程中是用的类和方法所需要的静态文件。永久代也被称为方法区,方法区的回收内容主要是 废弃常量和无用的类。
3.3 分代垃圾回收过程
上面我们理解了为什么要分代回收和回收的基本操作,下面展示具体回收过程:
1. 一个新的对象分配内存并记录在 Eden
区域
2. 当 Eden
区域占满,触发一次 minor GC
3. 被引用对象移动到第一块 Survivor 区域(S0)
,没有被引用的对象则被删除
4. 在下一次 Minor GC
,类似上一步没有被引用的对象被释放,Eden
和 引用对象则会被一起移动到第二块 Survivor 区域(S1)
,移动后,Eden
和 S0
被清空,可以看到现在 S1
区域有不同age的对象。
5. 下次 Minor GC
,同样的流程重复。但是这次 S0
和 S1
互换。引用的对象会被移动到 S0
,幸存的对象 age 继续增加,Eden
和 S1
都被清空。
6. 经过几次 Minor GC
之后,对象age达到阈值(这里为8),他们就会被移动到老年代
7.随着Minor GC
不停地进行,幸存的对象持续promote到老年代
8. 随着老年代
的对象不断增多,最终会触发 Major GC
来释放更多的内存空间。
相关文章:

Java 垃圾回收
文章目录 1 Java 垃圾回收1.1 JVM1.2 Java 对象生命周期 2 如何判断一个对象可被回收2.1 引用计数算法2.2 可达性分析算法 3 垃圾回收过程3.1 总体过程3.2 为什么要进行世代垃圾回收?3.3 分代垃圾回收过程 在 C 和 C 中,许多对象要求程序员声明他们后为其…...

多客陪玩系统-开源陪玩系统平台源码-支持游戏线上陪玩家政线下预约等多场景应用支持H5+小程序+APP
多客陪玩系统-开源陪玩系统平台源码-支持游戏线上陪玩家政按摩线下预约等多场景应用支持H5小程序APP 软件架构 前端:Uniapp-vue2.0 后端:Thinkphp6 前后端分离 前端支持: H5小程序双端APP(安卓苹果) 安装教程 【商业…...

书生·浦语大模型全链路开源体系-笔记作业2
全部写成了shell脚本,可以一键执行。 笔记: 1. 环境安装(InternStudio开发机) # 1. 创建conda环境 studio-conda -o internlm-base -t demo # 2. 激活conda环境 conda activate demo # 3. 安装额外的依赖 pip install huggingface-hub0.17.3 pip inst…...
手把手教你发布你的第一个npm插件包
在开源的世界里,npm(Node Package Manager)不仅是JavaScript生态中不可或缺的一部分,也是全球最大的软件注册表,它使得分享和复用代码变得异常简单。如果你有一个很棒的想法或者实用的功能想要封装成一个npm包供他人使…...

Docker-compose 编排lnmp(dockerfile) 完成Wordpress
一、部署 Nginx 镜像 1. 建立工作目录 mkdir /opt/lnmp/nginx -pcd /opt/lnmp/nginx#上传 nginx 安装包 nginx-1.12.0.tar.gz#上传 wordpress 服务包 wordpress-4.9.4-zh_CN.tar.gz mkdir /opt/lnmp/nginx/htmltar zxvf wordpress-4.9.4-zh_CN.tar.gz -C /opt/lnmp/nginx/html…...

秋招突击——算法打卡——5/28——复习{Z字形变换、两数之和}——新做:{整数反转、字符串转整数}
文章目录 复习Z字形变换实现代码参考代码 两数之和复习代码 新作整数反转个人实现实现代码 参考做法字符串转换整数个人解法 分析总结 复习 Z字形变换 实现代码 这里使用了他的思想,但是没有用他的代码,虽然已经比上次简洁了,但是还是不够&…...

PPT设置为本框的默认格式以及固定文本框
调整文本框固定位置 双击文本框之后勾选如下三个位置 设置文本框为默认 在调整好文本框的基本性质后,设置为默认即可...

计算机基础(5)——进制与进制转换
💗计算机基础系列文章💗 👉🍀计算机基础(1)——计算机的发展史🍀👉🍀计算机基础(2)——冯诺依曼体系结构🍀👉ἴ…...

发现情绪背后的真实心理需求,选择适合你的情绪调节方式
一、教程描述 心态对人的生活质量以及身体健康等多方面,都会产生非常重要的影响,受到不良情绪的影响,人的心态也会发生一定的变化。对于处于不良情绪状态的人来讲,应该重视学会调整自己的情绪。在心理学上,人的每种情…...

代理记账公司的五大问题及其解决方案
代理记账公司是现代企业管理中不可或缺的一部分,它为企业的日常运营提供了专业、高效的服务,随着行业的发展和竞争的加剧,代理记账公司的面临的问题也日益突出,这些问题主要表现在以下几个方面: 业务流程不规范 许多代…...

TH方程学习 (7)
一、内容介绍 TH存在广泛应用,在下面案例中,将介绍几种相对运动模型,斜滑接近模型,本节学习斜滑接近制导方法能够对接近时间、接近方向以及自主接近过程的相对速度进行控制。施加脉冲时刻追踪器的位置连线可构成一条直线…...

2024最新python入门教程|python安装|pycharm安装
前言:在安装PyCharm之前,首先需要明确PyCharm是一款功能强大的Python集成开发环境(IDE),由JetBrains公司开发。PyCharm旨在通过提供智能代码补全、语法高亮、代码检查、快速导航和重构等丰富的编码辅助工具,…...
docker架构
docker架构 Docker daemon 是Docker最核心的后台进程,它负责响应来自Dockerclient的请求,然后将这此请求翻译成系统调用完成容器管理操作。该进程会在后台后启动一个APIServer,负责接收由 Dockerclient发送的请求;接收到的请求将通…...

使用Java进行网络采集:代理IP与参数传递详解
在Java编程语言中,参数传递机制是一个常见的讨论话题。理解这一点对于编写高效且无错误的Java代码至关重要。本文将探讨Java的参数传递机制,解析其究竟是“按引用传递”还是“按值传递”,并结合网络爬虫技术的实例,展示如何在实际…...

多功能光时域反射仪的工作原理
6426A-2101多功能光时域反射仪是新一代掌上型智能化光纤通信测量仪器,具有强大的功能和广泛的应用领域。它能够显示光纤及光缆的损耗分布曲线图,测量光纤及光缆的多种关键参数,包括长度、损耗、接续质量等,为光纤通信系统的工程施…...

目标检测数据集 - 海洋垃圾检测数据集下载「包含VOC、COCO、YOLO三种格式」
数据集介绍:海洋垃圾检测数据集,真实拍摄海洋海底场景高质量垃圾检测图片数据,涉及场景丰富,比如海底塑料垃圾数据、海底铁制品罐状垃圾数据、海底纸张垃圾数据、海洋生物和海底垃圾同框数据、海底探索仪器和海底垃圾同框数据、海…...
如何进行Java程序的性能优化
在软件开发中,性能优化是一个至关重要的环节,它直接影响到用户体验、系统稳定性和资源消耗。对于Java程序而言,性能优化更是不可或缺的一部分。下面,我将从技术难点、面试官关注点、回答吸引力和代码举例四个方面,详细…...

Echarts柱状图数据太多,自定义长度之后,自适应浏览器缩放
不知道是不是最优解,但是当前解决了我遇到的问题,如有更好的方法,希望看到这篇文章的同学可以不吝指导一番,非常感谢 1、问题描述: 因Ecahrts柱状图数据有时多有时少,所以在数据达到一定程度之后ÿ…...

小白级教程—安装Ubuntu 20.04 LTS服务器
下载 本教程将使用20.04版进行教学 由于官方速度可能有点慢,可以下方的使用清华镜像下载 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/ 点击20.24版本 选择 ubuntu-20.04.6-live-server-amd64.iso 新建虚拟机 下载好后 我们使用 VMware 打开它 这里选…...
9、中华人民共和国个人信息保护法
第一章 总 则 第一条 为了保护个人信息权益,规范个人信息处理活动,促进个人信息合理利用,根据宪法,制定本法。 第二条 自然人的个人信息受法律保护,任何组织、个人不得侵害自然人的个人信息权益。 第三条 在中华人民共和国境内处理自然人个人信息的活动,适用本…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...