当前位置: 首页 > article >正文

JVM的垃圾回收机制GC

垃圾回收机制,是java对于内存自动回收的机制。但是呢,这不是java独创的。


GC回收的是内存,更准确的来说是对象,回收的是堆上的内存。

那么释放哪几块内存区呢?

1)程序计数器(不需要进行额外的回收,线程销毁,自然就回收了)。

2)栈(不需要进行额外的回收 ,线程销毁,自然就回收了)。

3)元数据区(一般也不需要,都是加载类,很少卸载类)。

4)堆(GC回收的主力部分)(这里我们主要回收的就是对象,new出来的都是在堆中的)。

GC的流程主要有两个步骤:

1. 找到谁是垃圾。

2. 释放所对应的内存。


GC机制的两种实现方法


引用计数法


这里的引用计数法并不用jvm采取的方案,但这里的引用计数法非常的简单。

例如,当我们创建对象是如:Test a = new Test() , 这里对象本身的计数器就会加一。

当我们再写一个 Test b = a 时,这里我们的计数器就会再加一,变成2。

如图解:

当我们都将a 和 b 置为空是,这里的计数器就减一减一,变成零。

如图:

引用计数变成零,这里就可以视作为垃圾了。

但是这个方法有两个缺陷:

(1)消耗额外的存储空间(如果你的对象比较大还好,但如果你的对象比较小,且数目比较多的话,那么消耗的额外空间就比较多了)

(2)循环引用的问题(比较重要)


循环引用问题解释:

如代码:

class Test{
   Test t;
}

  Test a = new Test();
  Test b = new Test();
  a.t = b;
  b.t = a;
  a = null;
  b = null;

如上图代码,a和b的引用都被引用了两次,计数器上的数字为2。

但当我们,对a和b赋值为空的时候,计数器都减一,变成一,但这里就可以视作为垃圾释放了,但计数器为一,释放不掉,就会出现问题了。

如图:

所以两个引用相互指向对方,外面的代码也无法访问到,就会出现这种问题。


可达性分析(JVM采取的方案)


可达性分析呢,解决了存储空间的问题,也解决了循环引用的问题 

JVM把对象之间的引用关系,理解成了树形的结构。

JVM就会不停的遍历这样的结构,能遍历到的标记为可达,不能被标记到的标记为不可达。

这里就像是数据结构中的,从根节点触发,所有的叶子节点都是可达的。

如果后续叶子节点没有遍历到,那么就是不可达的了。

如果根节点为空了,那么都是不可达的了,那么全都视为垃圾了。


还有这里的树型结构是自己创建的,本身就存在的,不是虚构的。

如图:


释放垃圾的策略


(1)标记清除


标记清除就是把对应垃圾的对象所对应的内存释放,简单粗暴。

如图:

这样的有什么后果呢,从图中可以分析,释放垃圾后,会存在大量的内存碎片。

当我们后面创建对象时,需要申请一大块空间时,就会影响到。

所以这种算法并不实用。


(2)复制算法


这里的复制算法,比如,我们的一段内存空间,有的是垃圾,那么我们会把不是垃圾的对象所对应的内存,复制到另一块的内存空间上,然后对原来的一块内存,全部释放掉。

如图:

释放后:

这里最大的问题就是,空间浪费的太多了。


(3)标记整理


这里的标记清理,类似于搬运,就是一块空间,垃圾释放掉之后,会把不是垃圾的放到一块。

如图:

这样的处理方法解决了时间的问题,但是时间开销更大了。


基于上述的这三种策略,又有了一个更复杂的策略。分代回收。


分代回收


分代算法和上面讲的3种算法不同,分代算法是通过区域划分,实现不同区域和不同的垃圾回收策 略,从而实现更好的垃圾回收。这就好比中国的⼀国两制方针⼀样,对于不同的情况和地域设置更符合当地的规则,从而实现更好的管理,这就时分代算法的设计思想。

当前JVM垃圾收集都采用的是"分代收集(Generational Collection)"算法,这个算法并没有新思想, 只是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代。在新生代 中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。

如图:

(1)伊甸区 ->生存区 通过复制算法。(由于存活对象很少, 复制开销也很低, 生存区空间也不必很大)。
(2)生存区 ->另一个生存区 通过复制算法,没经过一轮 GC,生存区中都会淘汰掉一批对象,剩下的通过复制算法,进入到另一个生存区(进入另一个生存区的还有从伊甸区里进来的对象)。
存活下来的对象,年龄 +1
(3)生存区 -> 老年代 某些对象, 经历了很多轮 GC, 都没有成为垃圾,就会复制到 老年代 ~~


老年代的对象,也是需要进行 GC 的,但是老年代的对象生命周期都比较常,就可以降低 GC扫描的频率。上述的过程就是分代回收的基本算法逻辑。


http://www.kler.cn/a/451009.html

相关文章:

  • 圣诞节文化交流会在洛杉矶成功举办
  • DX12 快速教程(2) —— 渲染天蓝色窗口
  • 本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——12使用YOLO-Bin
  • OpenCV学习——图像融合
  • 从AI换脸到篡改图像,合合信息如何提升视觉内容安全?
  • 使用GPT进行SCI论文润色常用语句
  • 面试基础篇---迭代器,yield, tcp, 等
  • C调用gnuplot绘图的方法
  • 【ROS2】坐标TF变换工具-tf2_ros
  • 鸿蒙元服务从0到上架【第三篇】(第二招有捷径)
  • tortoisegit推送失败
  • ubuntu下 如何将 NVIDIA 内核驱动 升级到特定版本 如550.127
  • 大语言模型学习工具及资源总结和落地应用
  • soular使用教程
  • ONNX 转 TensorRT Bug 记录:IIfConditionalOutputLayer
  • 鸿蒙-什么是ArkTS
  • 【C++】模板与泛型编程(一):定义模板,类模板
  • vue3 + MapTalks实现2.5D地图的绘制
  • SQL Server数据库多主模式解决方案
  • 面试小札:Java后端闪电五连鞭_11
  • prometheus监控windows主机
  • Springboot基于Web的高校志愿者服务管理系统81559
  • Git安装及基础学习
  • Blazor 中调用 JavaScript
  • 20241224在ubuntu20.04.6下的终端分屏软件terminator的安装以及使用
  • 网络安全词云图与技术浅谈