JVM主要的几种垃圾回收算法

1、Java 为什么要实现自动内存管理 ?

简化开发过程:通过内存自动管理可以避免手动分配和释放内存的麻烦,减少了内存泄漏和内存错误的风险,让研发能更专注于业务逻辑,不必纠结于内存管理的细节。

提高开发效率:垃圾回收器(Garbage Collector)能够自动追踪不再使用的对象,并释放它们占用的内存。这消除了手动跟踪和释放对象的需要,减少了开发人员的工作量,提高了开发效率。

可移植性好:研发人员不需要关心不同平台的内存管理差异,这些细节都交由虚拟机和垃圾回收器进行处理,Java的内存管理机制使得Java程序在不同的平台上运行更加容易。

2、java 自动内存管理并不是一劳永逸

Java的自动内存管理机制(垃圾回收器和垃圾回收算法的设计),确实可以大大简化开发人员对内存管理的工作,同样也带来了一系列的问题

内存占用和性能问题:不合适的内存使用、配置,可能导致内存占用过高或性能下降。如,长生命周期对象、内存泄漏、过频繁的垃圾回收等,都会影响应用程序的性能和稳定性。

垃圾回收停顿:虽然垃圾回收器一直都在优化减少停顿时间,但并不能完全消除。实时性要求高的系统对停顿时间很敏感

所以我们需要搞懂JVM内存管理机制,才能针对不同的场景合理使用

3、垃圾回收的机制

a、垃圾回收发生在哪里 ?

JVM 内存模型中程序计数器、栈、本地方法栈这 3 个区域是线程私有的,与线程同生共死,不涉及回收,所以垃圾回收的就在剩下的堆和方法区中了,堆中主要回收是对象,方法区的回收则主要是废弃常量和无用的类

b、什么情况下对象可以被回收?

JVM认为一个对象不再被引用,就代表该可以被回收了,目前有两种算法可以判断该对象是否可以被回收。

引用计数算法 :通过对象的引用计数器判断对象是否被引用。即每当对象被引用时,该对象的引用计数器就会 + 1; 当引用失效时,计数器再 -1。对象引用计数器值为 0 时,表示该对象不再被引用,可以被回收。引用计数算法的实现简单,判断效率也很高,但它存在对象之间循环引用的问题。

可达性分析算法: 在垃圾回收时,以 GC Roots 对象为根对象开始遍历对象图,确定哪些对象是可达的(即不会被回收),而哪些对象是不可达的(即可被回收)。目前 HotSpot 虚拟机采用的就是这种算法。

c、哪些是 GC Roots 对象 ?

虚拟机栈(栈帧中的本地变量表)中引用的对象:当前线程中方法调用链上的所有对象。

方法区中的类静态属性引用的对象:被类声明为静态变量的对象。

方法区中常量引用的对象:被常量池中的常量引用的对象。

本地方法栈中引用的对象:在Java代码中调用本地方法后,本地方法中引用的对象

GC Roots 本身是不可被回收的,它们的存在保证了从根节点出发的对象的可达性。垃圾回收器通过追踪GC Roots对象的引用链,可以确定哪些对象是可达的,而哪些对象是不可达的,从而进行垃圾回收操作。

4、垃圾回收的三种方式

a、标记-清除算法(Mark and Sweep)

把垃圾对象所占据的内存标记为空闲内存,并记录在一个空闲列表(free list)中。当需要新建对象时,内存管理模块便会从该空闲列表中寻找空闲内存,并划分给新建的对象。该回收方式的原理非常简单,但会带来俩个缺点

内存碎片化:由于 Java 虚 拟机的堆中对象必须是连续分布的,因此可能出现总空闲内存足够,但是无法分配的极端情

内存分配效率低:如果是一块连续的内存空间,那么我们可以通过指针加法 (pointer bumping)分配。但对于空闲列表,Java 虚拟机则需要逐个访问列表中的项,来查找能够满足新建对象的大小的空闲内存

b、标记-整理算法(Mark and Compact)

在标记阶段(Mark)也会标记所有可达对象。然后,在整理阶段(Compact),将存活的对象压缩(Compact)到堆的一端,以释放不连续的内存空间。这种做法能够解决内存碎片化的问题,但代价是压缩算法的性能开销。

c、复制(copy)

把内存区域分为两等分,分别用两个指针 from 和 to 来维 护,并且只是用 from 指针指向的内存区域来分配内存。当发生垃圾回收时,便把存活的对 象复制到 to 指针指向的内存区域中,并且交换 from 指针和 to 指针的内容。复制这种回收方式同样能够解决内存碎片化的问题,但是它的缺点也极其明显,即堆空间的使用效率极其低下。

d、分代回收算法(Generational)

分代算法基于对象的生命周期将堆内存分为不同的代,如新生代和老年代。新生代中的对象通常具有较短的生命周期,而老年代中的对象具有较长的生命周期。不同代使用不同的垃圾回收算法,以便更好地适应对象的特性和内存使用模式。

G1的三种GC模式

young GC:当所有 eden region 被消耗无法再申请时触发一次young GC,活对象被拷贝到survivor region 或者晋升到 old region

mixed GC:回收整个young region,同时回收一部分old region。老年代占用达到一定阈值的时候触发

full GC:对象内存分配过快,mixed GC来不及回收,导致老年代被填满,会触发一次full GC

JVM在应用垃圾回收器时往往会综合上述几种回收方式,综合它们优点的同时规避它们的缺点,达到比较优的内存管理方式

相关推荐
guihong00419 分钟前
JAVA面试题、八股文学习之JVM篇
java·jvm·学习
gogo_hua1 小时前
JVM系列之OOM观测准备
java·大数据·jvm
柯34919 小时前
GC垃圾回收
java·jvm·垃圾回收
王佑辉19 小时前
【jvm】执行引擎是做什么
jvm
平头哥在等你19 小时前
C语言简答题答案
java·c语言·jvm
zhuzhihongNO121 小时前
JVM(JAVA虚拟机)内存溢出导致内存不足,Java运行时环境无法继续
java·开发语言·jvm·内存溢出·jvm内存溢出
MaxCosmos200121 小时前
读《Effective Java》笔记 - 条目7
java·jvm·笔记
学点东西吧.21 小时前
JVM(六、Java内存分配)
java·开发语言·jvm
极客先躯1 天前
高级java每日一道面试题-2024年11月23日-JVM篇-什么时候会出发FullGC?
java·jvm·fullgc·jvm篇·老年代内存不足·system.gc·减少full gc的策略