JVM 的垃圾回收机制以及垃圾回收算法的详解

简介: JVM 的垃圾回收机制以及垃圾回收算法的详解

1、JVM 的垃圾回收机制

对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。


因此有关内存分配和回收关注的为堆区和方法区这两个区域。


垃圾回收,就是回收内存。而 JVM 中的内存又分为好几块:

1、程序计数器,由于程序计数器占用的内存空间小,不需要“垃圾回收”。

2、栈区,局部变量都是在代码块执行结束后自动销毁,这和“垃圾回收”没有关系。

3、元数据区 / 方法区,一般都是涉及到“类加载”,很少涉及到“类卸载”,少量使用到“垃圾回收”。

4、堆区,“垃圾回收”的主要战场。



2、识别垃圾

想要回收垃圾,首先要识别出垃圾。在 Java 中,使用对象一定需要通过引用的方法来使用(除了匿名对象,执行完匿名对象那行代码后,对应的对象就会被当作垃圾),如果一个对象没有任何引用指向它,就视为是无法被代码使用的,即可以当作垃圾。


但是,如果代码复杂一些,这些引用的生命周期各不相同,此时识别垃圾的判定过程就会复杂一些。为了解决这个问题,引入了两种解决方法:


2.1、引用计数

给每个对象安排一个额外的空间,空间里要保存当前这个对象有几个引用。这种思想虽然并没有在 JVM 中使用,但是广泛应用于其他主流语言的垃圾回收机制中(Python、php)。



引用计数机制,是一个简单有效的机制,但是存在两个关键的问题:


  • 问题一:消耗额外的内存空间。
  • 问题二:引用计数可能会产生“循环引用”的问题,此时引用计数就无法正常工作。所谓“循环引用”是指类似于:一个类中的一个成员变量指向另一个类的引用,另一个类中的成员变量同样又指向这个类的引用,当将原先引用类的变量置空,此时引用计数依然不为0。


上述代码出现了问题,此时两个对象的引用计数都不是0,不能被 GC 回收掉,但是这两个对象又无法使用,出现了类似“死锁”的情况,这也是 Java 不用引用计数的原因之一。


2.2、可达性分析

本质上是用“时间”换取“空间”,相比引用计数需要消耗更多的额外空间,但总体来说是可控的,不会产生类似“循环引用”的问题。


在写代码的过程中会定义很多变量,就可以从这些变量作为起点入手,尝试进行“遍历”,所谓遍历就是沿着变量中持有的引用类型的成员,再进一步的往下进行访问。


JVM 中存在专门的扫描线程,会不停的尝试对代码中已有的变量进行遍历,尽可能多的访问到对象。



使用上图举例,root 指向这棵二叉树的根节点,如果代码中出现了 root.right.right = null,此时二叉树与 f 节点断开,无法再使用 root 出发进行遍历操作访问 f 了,此时就说 f 节点为 “不可达” ,即可称为是垃圾;同样的代码中出现 root.right = null,此时二叉树与 c 节点断开,此时无法使用 root 遍历到达 c 节点,自然也无法到达 f 节点,此时就说 c 和 f 都是垃圾。


因此,所有能被访问到的对象,自然就不是垃圾了,反之剩下遍历了一圈也访问不到的对象,就是垃圾。


3、垃圾回收算法

把标记为垃圾的对象的内存空间进行释放,主要的释放方式有三种。


3.1、标记-清除

把标记为垃圾的对象直接释放掉(最朴素的做法),但是会产生内存碎片。如果存在很多内存碎片,很可能导致申请内存空间失败的情况。

因此一般不会使用这种方案,因为“内存碎片问题”是比较致命的。



3.2、复制算法

核心是不直接释放内存,而是把不是垃圾的对象,复制到内存的另外一半中,然后再整体将左则空间整体释放掉。



复制算法确实能够规避内存碎片问题,但是也有缺点:


  • 因为需要留有空间进行复制操作,总的可用内存变少了。
  • 如果每次要复制的对象比较多,此时复制的开销就会很大。(只有当该轮 GC 过程中,有大量对象被释放,少数对象存活,此时才适合使用“复制算法”)

3.3、标记-整理

类似于顺序表删除中间元素的操作(向前搬运),通过这个过程也能够有效解决内存碎片问题,也没有复制算法需要浪费很多空间,但是搬运内存的开销非常大。



由于这三种释放方式都存在各自的问题,因此 JVM 并没有直接使用上述方式,而是结合上述思想取长补短,做出了综合性方案,称为“分代回收”。


4、分代回收

引入了“对象的年龄”这样的概念,JVM 中有专门的线程负责周期性扫描/释放,一个对象如果被线程扫描一次,并且“可达性分析”证明可达(不是垃圾),此时将该对象的年龄属性 + 1(初始年龄为0)。JVM 中根据年龄的差异,将整个堆内存分成两个大的部分,“新时代”和“老年代”。而新生代区中又分为“伊甸区”、“生存区s0”和“生存区s1”。



当代码中 new 出一些对象,这些对象会先被创建在伊甸区,而在伊甸区中的对象,绝大部分会死去,只有少量存活,因此此处的垃圾回收算法使用“复制算法”。


然后经过一轮 GC 扫描后,会有少数存活的对象通过“复制算法”拷贝到生存区(有两个生存区),后续的 GC 扫描线程会对伊甸区和生存区都进行扫描,伊甸区中少数存活的对象同样会进入生存区,而生存区中仍然存活的对象会拷贝到另外一个生存区。


当对象的年龄达到一定阈值(一般情况默认 15 次)并且依然存活时,此时 JVM 就会认为该对象的生命周期大概率很长,就将这个对象从生成区拷贝到老年代区。


而在老年代的对象,GC 扫描的频率会大大降低。在老年代中结束的对象会按照 JVM的“标记整理”或者“标记清除”方法释放内存。



目录
相关文章
|
24天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
31 0
|
1天前
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
23天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
27天前
|
机器学习/深度学习 监控 算法
Java虚拟机(JVM)的垃圾回收机制深度剖析####
本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
41 1
|
1月前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
42 5
|
1月前
|
存储 算法 Java
JVM进阶调优系列(10)敢向stop the world喊卡的G1垃圾回收器 | 有必要讲透
本文详细介绍了G1垃圾回收器的背景、核心原理及其回收过程。G1,即Garbage First,旨在通过将堆内存划分为多个Region来实现低延时的垃圾回收,每个Region可以根据其垃圾回收的价值被优先回收。文章还探讨了G1的Young GC、Mixed GC以及Full GC的具体流程,并列出了G1回收器的核心参数配置,帮助读者更好地理解和优化G1的使用。
|
1月前
|
算法 Java
JVM有哪些垃圾回收算法?
(1)标记清除算法: 标记不需要回收的对象,然后清除没有标记的对象,会造成许多内存碎片。 (2)复制算法: 将内存分为两块,只使用一块,进行垃圾回收时,先将存活的对象复制到另一块区域,然后清空之前的区域。用在新生代 (3)标记整理算法: 与标记清除算法类似,但是在标记之后,将存活对象向一端移动,然后清除边界外的垃圾对象。用在老年代
23 0
|
2天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
105 80
|
21天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
7天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。