JVM的垃圾回收算法一起来看看

 更新时间:2022年3月8日 17:16  点击:286 作者:吃鱼的宗介

垃圾回收算法

概念

垃圾回收(Garbage Collection,GC)。程序的运行需要资源,无效的对象如果不及时清理就会一直占用资源,所以对内存资源管理就变得十分重要。而Java为了让我们更多的关注代码本身,而不用过多的考虑内存的释放问题,就有了我们十分熟悉的GC。然而当垃圾回收成为系统达到更高并发量的瓶颈时,我们就需要对这些自动化的技术进行一系列的监控和调节。 

GC主要需要完成三件事情 :

哪些内存需要回收?
什么时候回收?
如何回收?

哪些垃圾需要回收呢?这个时候我们如何判断哪些对象“活着”,哪些对象“死去”?于是就有了标记算法。

1.标记算法

垃圾收集器中标记算法有两种,引用计数法和根可达算法

1.1 引用计数法(Reference Counting)

引用计数算法很简单,它实际上是通过在对象头中分配一个空间来保存该对象被引用的次数。如果该对象被其它对象引用,则它的引用计数加1,如果删除对该对象的引用,那么它的引用计数就减1,当该对象的引用计数为0时,那么该对象就会被回收。

如:

A objA = new A();
B objB = new B();
objA.ref = objB;

如图:

在这里插入图片描述

对象 A 的实例在Java堆中就是一块内存而已,而objA 做为一个局部变量引用了它,所以它的引用计数就是1,对象B的实例在堆中也是一块内存,objB这个局部变量引用了它,然后objA又引用了它一次,所以它的引用计数就是2。

客观来说,引用计数算法 效率高,实现简单,然而,Java虚拟机没有选取引用计数算法来管理内存,主要是因为无法解决 循环引用的问题

如:

objA.ref= objB;
objB.ref= objA

如图:

在这里插入图片描述

实际上这两个对象已经不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为0,于是这两个对象都无法被GC回收。

1.2 可达性分析算法(Reachable Analysis)

在Java中是通过可达性分析算法来判断对象是否存活的。选定一系列称为"GC ROOTS"的对象作为起始点,从这些对象向下搜索,搜索所走过的道路称为引用链(Reference Chain).当一个对象到GC ROOTS没有任何引用链时,则不可达,这些对象会被判定可以回收。

如图:

在这里插入图片描述

在Java中,能作为GC Roots的对象包含以下几种

虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈JNI(即一般说的Native方法)当中引用的对象

2.回收算法

当成功区分出哪些是存活对象哪些是死亡对象之后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对象分配内存。常用的垃圾回收算法有 标记清除算法、复制算法、标记压缩算法。

2.1 标记清除算法 (Mark Sweep)

标记清除算法是最基础的垃圾回收算法,同它的名字一样,该算法有两个过程,首先标记哪些是可回收的对象,然后进行内存回收

标记: Collector从引用根结点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。

清除: Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。从网上找张图给大家解释一下,

如图:

在这里插入图片描述

缺点:

1.效率不高,标记过程和清除过程效率都一般

2.会产生很多空间碎片,可能会导致以后为大对象分配空间时因为找不到可用的连续内存空间不得不再次进行GC。

2.2 复制算法(Copying)

GC复制算法(Copying GC)是由Marvin L. Minsky在1963年研究出来的算法。原理是把内存分为两个空间一个是From空间,一个是To空间,对象一开始只在From空间分配,To空间是空闲的。GC时把存活的对象从From空间复制粘贴到To空间,之后把To空间变成新的From空间,原来的From空间变成To空间。回收前后对比下图所示:

如图:

在这里插入图片描述

优缺点:

1.复制算法实现简单运行高效,不会产生内存碎片

2.但是将内存缩小为原本的一半,代价略高。

现在虚拟机基本都采用这种垃圾回收算法回收新生代

2.3 标记压缩算法(Mark-Compact)

标记压缩算法(Mark-Compact),标记过程和标记清除算法的标记过程一样,但是清理过程不同,会将存活对象移动到一端,然后清理掉端边界之外的内存,

如图:

在这里插入图片描述

优缺点:

标记整理算法效率低,但不用浪费内存,也不会造成内存碎片。

2.4 分代回收算法

在这里插入图片描述

因为新生代对象大量死去,少量存活,一般采用复制算法。老年代存活率高,回收的少,一般采用MC/MS(标记清除/标记压缩)

在这里插入图片描述

如图是我用arthas的dashboard命令输出的本地的Memory信息。jdk1.8默认的垃圾回收器是ps+po(这个之后讲)。可以看到新生代大小(伊甸区和s区),老年代大小。

2.4.1 新生代(Eden区/伊甸区)

年轻代的对象处于一种“朝生夕死”的状态,在年轻代的GC叫做YGC(Minor GC)。Eden区对象活过第一次垃圾回收之后会进入survivor区(S0S1/S1S2)。在S1,S2之间经过多次垃圾回收进入老年代。

-XX:MaxTenuringThreshold 可以配置多少次从年轻代进入老年代

在这里插入图片描述

在多线程那我们整过这张图,再看一下,分代年龄只有4bit,意味着对象的最大年龄只有15-----可以通过上面的参数设置大小,最大15,之后要是没有被gc就会进入老年代。

2.4.2 老年代(tenured/old)

进入老年代的对象大多数活过了年轻代的多次gc,因此不会频繁死亡,老年代的GC叫做(Major GC)FULL GC。FGC的效率比YGC低的多,在老年代无法继续分配空间的时候触发,触发是新生代老年代一起进行回收。

2.4.3 新生代何时进入老年代

1. 超过 XX:MaxTenuringThreshold 指定次数
2. 动态年龄,S0->S1超过50%,把年龄最大的放到Old
3. 分配担保:YGC期间,survivor区空间不够了,空间担保直接进入老年代

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注猪先飞的更多内容!  

原文出处:https://blog.csdn.net/qq_38895905/article/details/122527967

[!--infotagslink--]

相关文章

  • C#几种排序算法

    作者:Sabine 【导读】本文介绍了C#的四种排序算法:冒泡排序、选择排序、插入排序和希尔排序  冒泡排序 using System; namespace BubbleSorter { public class Bubb...2020-06-25
  • 经典实例讲解C#递归算法

    这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
  • C#中实现任意List的全组合算法代码

    这篇文章主要是介绍了.net C# 实现任意List的全组合算法实现代码,需要的朋友可以参考下...2020-06-25
  • 同时兼容JS和C#的RSA加密解密算法详解(对web提交的数据加密传输)

    这篇文章主要给大家介绍了关于同时兼容JS和C#的RSA加密解密算法,通过该算法可以对web提交的数据进行加密传输,文中通过图文及示例代码介绍的非常详细,需要的朋友们可以参考借鉴,下面来一起看看吧。...2020-06-25
  • 图文详解Heap Sort堆排序算法及JavaScript的代码实现

    这篇文章以图文详解Heap Sort堆排序算法及JavaScript的代码实现,堆排序算法基于类二叉树的堆数据结构,需要的朋友可以参考下...2016-05-05
  • C#常用数据结构和算法总结

    这篇文章主要介绍了C#常用数据结构和算法,这里我们总结了一些知识点,可以帮助大家理解这些概念。...2020-06-25
  • JS实现的随机排序功能算法示例

    这篇文章主要介绍了JS实现的随机排序功能算法,结合具体实例形式分析了javascript常用的排序算法实现技巧,需要的朋友可以参考下...2017-06-15
  • C++实现的O(n)复杂度内查找第K大数算法示例

    这篇文章主要介绍了C++实现的O(n)复杂度内查找第K大数算法,结合实例形式分析了算法的原理以及具体实现方法,需要的朋友可以参考下...2020-04-25
  • c# 实现位图算法(BitMap)

    这篇文章主要介绍了c# 如何实现位图算法(BitMap),文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-11-03
  • 一篇文章带你搞懂Vue虚拟Dom与diff算法

    这篇文章主要给大家介绍了关于Vue虚拟Dom与diff算法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-08-26
  • R语言关于随机森林算法的知识点详解

    在本篇文章里小编给大家整理的是一篇关于R语言关于随机森林算法的知识点详解内容,有兴趣的朋友们可以跟着学习下。...2021-05-13
  • C++并查集亲戚(Relations)算法实例

    这篇文章主要介绍了C++并查集亲戚(Relations)算法,实例分析了并查集亲戚算法的原理与实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-04-25
  • C/C++实现八大排序算法汇总

    这篇文章主要为大家详细介绍了C/C++实现八大排序算法汇总,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • 基于稀疏图上的Johnson算法的详解

    本篇文章介绍了,稀疏图上的Johnson算法的详解。需要的朋友参考下...2020-04-25
  • C# URL短地址压缩算法及短网址原理解析

    这篇文章主要介绍了C# URL短地址压缩算法及短网址原理解析,本文重点给出了算法代码,需要的朋友可以参考下...2020-06-25
  • VC++实现选择排序算法简单示例

    这篇文章主要介绍了VC++实现选择排序算法简单示例,代码简洁易懂,有助于读者对数据结构与算法的学习,需要的朋友可以参考下...2020-04-25
  • 浅谈Java自定义类加载器及JVM自带的类加载器之间的交互关系

    这篇文章主要介绍了浅谈Java自定义类加载器及JVM自带的类加载器之间的交互关系,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-22
  • php回溯算法计算组合总和的实例代码

    在本篇文章里小编给大家整理的是一篇关于php回溯算法计算组合总和的实例代码,有需要的朋友们可以学习参考下。...2021-07-14
  • JavaScript常用数组算法小结

    在开发项目的过程中,我们经常会需要关于javascript数组的一些算法,比方说数组去重、数组求交集、数组扰乱等等。今天就把个人的汇总整理的算法分享给大家。...2016-02-18
  • C++基于递归算法解决汉诺塔问题与树的遍历功能示例

    这篇文章主要介绍了C++基于递归算法解决汉诺塔问题与树的遍历功能,简单描述了递归算法的原理,并结合实例形式分析了基于递归算法解决汉诺塔问题与数的遍历相关操作技巧,需要的朋友可以参考下...2020-04-25