写点什么

JVM 垃圾回收机制是怎样的,何时触发 YoungGC 或 FullGC 操作?

用户头像
Java鱼仔
关注
发布于: 2021 年 01 月 24 日

听说微信搜索《Java 鱼仔》会变更强哦!

本文收录于JavaStarter ,里面有我完整的 Java 系列文章,学习或面试都可以看看哦


(一)关于垃圾回收

JAVA 的垃圾回收需要完成三件事情:


1、哪些内存需要回收


2、什么时候回收


3、如何回收


下面就从这三个问题出发去了解 Java 的垃圾回收机制。


(二)哪些垃圾需要回收

在垃圾回收之前,首要的问题是确定哪些垃圾需要被回收,现在 Java 通过根搜索算法(GC Roots Tracing)来判断一个对象是否存活,这个算法的思路就是通过一系列名为“GC Roots”的对象作为起始点,从这些节点向下搜索,当 GC Roots 到达不了这个某个对象时(或者说某个对象没有被任何其他对象所引用),就证明这个对象是不可用的,这些对象会被判定为需要回收的对象。



如图,ObjC 是不可达的,这个对象就是需要被回收的对象。


在 Java 语言中,可作为 GC Roots 的对象包括下面这些:


1、虚拟机栈(栈帧中的本地变量表)中引用的对象


2、方法区中的类静态属性引用的对象


3、方法区中的常量引用的对象


4、本地方法栈(Native 方法)引用的对象


(三)什么时候回收

关于如何回收的问题,我参考了《深入理解 Java 虚拟机》,根搜索算法中不可达的对象,并不是立刻就会被回收,而是会经过一次标记:


如果对象没有覆盖 finalize()方法,或者 finalize()方法已经被调用,虚拟机会判定这个对象没必要执行 finalize(),在这一次标记中该对象不会被回收。


如果这个对象被标记为有必要执行 finalize()方法时,它会被放置在一个名为 F-Queue 的队列中,稍后由虚拟机进行垃圾回收。


但是这个对象还有最后一次逃脱的机会,当在 F-Queue 时,虚拟机会对 F-Queue 中的对象作小规模的标记,如果发现此时某个对象又可达了,就会逃过 GC 的命运。


(四)如何回收

如何回收垃圾的问题归根结底就是垃圾回收算法如何回收垃圾的问题。这里主要介绍三种垃圾回收算法的执行思路:


4.1 标记-清除算法(Mark-Sweep)

这种算法分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收掉被标记的对象。


看图就可以明白了,这个算法的问题在于,清除之后会产生大量不连续的空间碎片。


4.2 复制算法(Copying)

复制算法将内存分为两块,每次使用其中一块,垃圾回收时,将正在使用的那块内存中存活的内存放入另一块内存中,然后清空原内存块,图示图下:

复制算法被广泛应用于新生代的垃圾回收,由于新生代的对象有百分之 98 左右都是要被回收的,因此新生代的内存会被分为一块 Eden 空间和两块 Survivor 空间,比例为 8:1:1。


第一次 YGC 只回收 eden 区域,回收后大多数(百分之九十八左右)的对象会被回收,活着的对象通过复制算法进入 Survivor0(后续用 S0 和 S1 代替)。再次 YGC 后,eden+S0 中活着的对象进入 S1。再次 YGC,eden+S1 中活着的对象进入到 S0。依次循环


4.3 标记-整理(Mark-Compact)

标记-整理算法分为标记、整理、清除三步,第一步也是标记出可回收的对象,然后让存活的对象移到一边,然后直接清理掉边界外的垃圾。


标记整理算法被广泛应用于老年代的垃圾回收。


(五)何时触发 YoungGC 或 FullGC

YoungGC 的触发时常在发生,当新生代的 Eden 区满了之后就会触发 YoungGC。


FullGC 在多个情况下都会被触发:


1、发生 Young GC 之前进行检查,如果“老年代可用的连续内存空间” < “新生代历次 Young GC 后升入老年代的对象总和的平均大小”,说明本次 Young GC 后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,此时会触发 FullGC


2、当老年代没有足够空间存放对象时,会触发一次 FullGC


3、如果元空间区域的内存达到了所设定的阈值-XX:MetaspaceSize=,也会触发 FullGC。


发布于: 2021 年 01 月 24 日阅读数: 19
用户头像

Java鱼仔

关注

你会累是因为你在走上坡路 2020.12.26 加入

微信搜索《Java鱼仔》

评论

发布
暂无评论
JVM垃圾回收机制是怎样的,何时触发YoungGC或FullGC操作?