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

目录
  • 垃圾回收算法
    • 概念
    • 1.标记算法
      • 1.1引用计数法(ReferenceCounting)
      • 1.2可达性分析算法(ReachableAnalysis)
    • 2.回收算法
      • 2.1标记清除算法(MarkSweep)
      • 2.2复制算法(Copying)
      • 2.3标记压缩算法(Mark-Compact)
      • 2.4分代回收算法
  • 总结

垃圾回收算法

概念

垃圾回收(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区空间不够了,空间担保直接进入老年代

总结

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

(0)

相关推荐

  • JVM的垃圾回收算法工作原理详解

    怎么判断对象是否可以被回收? 共有2种方法,引用计数法和可达性分析 1.引用计数法 所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一.当一个对象的引用计数器为零时,说明此对象没有被引用,也就是"死对象",将会被垃圾回收. 引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,那么此时A,B对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法

  • JVM垃圾回收算法的概念与分析

    前言 在JVM内存模型中会将堆内存划分新生代.老年代两个区域,两块区域的主要区别在于新生代存放存活时间较短的对象,老年代存放存活时间较久的对象,除了存活时间不同外,还有垃圾回收策略的不同,在JVM中中有以下回收算法: 标记清除 标记整理 复制算法 分代收集算法 有了垃圾回收算法,那JVM是如果确定对象是垃圾对象的呢?判断对象是否存活JVM也会有几套自己判断算法了: 引用记数 可达性分析 有了垃圾回收和判断对象存在这两个概念后,再来逐步分析它们. JVM是如何判断对象是否存活的? 要是让开发人员来

  • 浅谈JVM垃圾回收有哪些常用算法

    一.前言: 垃圾回收: 在未来的JDK中可能G1会为ZGC所取代 先问自己几个问题: 什么是垃圾? 垃圾就是堆内存中(范指)没有任何指针指向的对象实体.不具有可达性. 为什么要回收垃圾? 因为我们的内存是有限的,内存长时间不清理就会导致内存溢出,OOM: 只要是程序正在跑,那么就不断生成新的对象,我们需要GC开辟新的空间分配给新的对象. 我们怎么回收垃圾? 依靠Java的自动内存回收机制,机制的优劣由算法决定: 或者说是机制的适配度由算法和应用场景共同决定. 什么时候回收垃圾? 当堆中的实体对象

  • 深入理解JVM垃圾回收算法

    目录 一.垃圾标记阶段 1.1.引用计数法 (java没有采用) 1.2.可达性分析算法 二.对象的finalization机制 2.1.对象是否"死亡" 三.使用(MAT与JProfiler)工具分析GCRoots 3.1.获取dump文件 3.2.GC Roots分析 四.垃圾清除阶段 4.1.标记-清除算法 4.2.复制算法 4.3.标记-压缩(整理,Mark-Compact)算法 4.4.以上三种垃圾回收算法对比 4.5.分代收集算法 4.6.增量收集算法 4.7.分区算法G1

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

    目录 垃圾回收算法 概念 1.标记算法 1.1引用计数法(ReferenceCounting) 1.2可达性分析算法(ReachableAnalysis) 2.回收算法 2.1标记清除算法(MarkSweep) 2.2复制算法(Copying) 2.3标记压缩算法(Mark-Compact) 2.4分代回收算法 总结 垃圾回收算法 概念 垃圾回收(Garbage Collection,GC).程序的运行需要资源,无效的对象如果不及时清理就会一直占用资源,所以对内存资源管理就变得十分重要.而Jav

  • 最新JVM垃圾回收算法详解

    目录 1.垃圾回收需要做什么 2.如何判断对象可被回收 2.1 引用计数算法 2.1.2 优点 2.1.2 缺点 2.2 可达性分析算法 2.2.1 算法思路 2.2.2 GC Roots对象(两栈两方法) 2.2.3 优点 2.2.4 缺点 3.判断对象生存还是死亡 3.1 两次标记过程 3.2 finalize()方法 4.HotSpot虚拟机中对象可达性分析的实现 4.1 枚举根节点 4.2 安全点 4.2.1 安全点是什么,为什么需要安全点 4.2.2 安全点的选定 4.2.3 如何在安

  • jvm垃圾回收算法详细解析

    目录 前言 几种常用的垃圾回收算法 1.引用计数法 2.根搜索算法 3.标记清除法(Mark-Sweep) 4.复制交换算法(Mark-Sweep) 5.标记压缩算法(Mark-Compact) JVM 分代收集算法 前言 相比C语言,JVM虚拟机一个优势体现在对对象的垃圾回收上,JVM有一套完整的垃圾回收算法,可以对程序运行时产生的垃圾对象进行及时的回收,以便释放JVM相应区域的内存空间,确保程序稳定高效的运行,但在真正了解垃圾回收算法之前,有必要对JVM的对象的引用做一个简单的铺垫 JVM对

  • 老生常谈java垃圾回收算法(必看篇)

    1.引用计数法(Reference Counting Collector) 1.1算法分析 引用计数是垃圾收集器中的早期策略.在这种方法中,堆中每个对象实例都有一个引用计数.当一个对象被创建时,且将该对象实例分配给一个变量,该变量计数设置为1.当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减1.任何引用计数器为0的对象实例可以被当作垃圾收集.当一个对象实例被垃圾收

  • JVM类加载,垃圾回收

    目录 类加载子系统 双亲委派模型 垃圾回收 判断对象已死 JDK1.2之后的四种引用类型: 1.强引用: 2.软引用: 3.弱引用: 4.虚引用: 常见的垃圾回收算法: 1.标记–清除算法:(Mark–Sweep) 2.标记–复制算法: 3.标记–整理算法: 常见的垃圾回收器: 新时代.老年代 为什么大对象会直接存在老年代? 总结 类加载子系统 classLoader 只负责对字节码文件的加载,至于是否可以运行,还要看执行引擎. 加载的类信息存放于方法区的内存空间,除了类信息之外,还会存放有运行

  • JVM的垃圾回收机制真是通俗易懂

    目录 堆内存的划分 划分区域的目的 一.新生区的垃圾回收机制 二.什么时候进入老年区呢? 1经历15次GC后进入老年区 2动态对象年龄判断 3大对象直接进入老年代 4MinorGC后存活的对象太多无法放入Survivor区了 三.老年区空间分配担保原则 四.老年区垃圾回收算法 五.垃圾回收器 总结 堆内存的划分 分为三个部分(以下名词表示同一个区): 新生区.新生代.年轻代 养老区.老年区.老年代 永久区.永久代 划分区域的目的 唯一目的就是优化GC性能. 如果没有分代,我们所有的对象都放在一块

  • JVM的垃圾回收机制你了解吗

    目录 一:回收堆内存 1.如何判定对象已死(可达性分析算法) 2.对象的引用级别 3.对象的死亡过程 二:垃圾回收算法 1.标记清除算法 2.标记复制算法 3.标记整理算法 三:垃圾收集器 1.G1(GarbageFirst) 总结 一:回收堆内存 1.如何判定对象已死(可达性分析算法) 当前主流的商用程序语言的内存管理子系统,都是通过可达性分析算法来判定对象是否存活的.这个算法的基本思路就是通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程

随机推荐