GC回收算法&GC回收器

目录
  • 垃圾标记
    • 引用计数法
    • 可达性分析(主流使用)
  • GC回收算法
    • 标记-清除算法(适合老年代)
    • 标记-复制算法(适合年轻代)
    • 标记-整理算法(适合老年代)
    • “因地制宜”——分代算法
  • GC回收器
    • Serial 回收器
    • Serial Old 回收器
    • ParNew回收器
    • Parallel Old回收器
    • Parallel Scavenge回收器
    • CMS收集器
    • G1回收器

垃圾标记

在回收垃圾前,需要判断哪些是垃圾,哪些不是。

引用计数法

原理:被引用+1,未被引用-1,为0时回收。

问题:无法解决循环引用的问题

  • 什么是循环引用?(环)

    A 引用了 B,B 引用了 C,C 引用了 A,它们各自的引用计数都为 1。但是它们三个对象却从未被其他对象引用,(假设有1000个对象时,这三个就是垃圾;如果只有4个对象,那么另外一个就是垃圾)只有它们自身互相引用。从垃圾的判断思想来看,它们三个确实是不被其他对象引用的,但是此时它们的引用计数却不为零。

可达性分析(主流使用)

通过GC Roots作为起点遍历,判断是否被引用。

GC Roots包括:

  • 虚拟机栈中引用的对象
  • 方法区静态属性引用的对象
  • 方法区常量引用的对象
  • JNI引用的对象(Native方法)

【引用的判定】

  • 强引用:抛异常也不回收
  • 软引用:内存空间不够就回收
  • 弱引用:发现了就回收(按线程优先级)
  • 虚引用:任何时刻都会被回收

GC回收算法

分代收集本质上就是分类讨论,根据对存活对象的预判,采用效率更高的收集算法。

标记-清除算法(适合老年代)

先通过GC Roots遍历,标记不可达对象,而后清除。

问题:产生不连续的空间碎片

标记-复制算法(适合年轻代)

折半内存,将存活对象复制到另一半内存中,然后把当前内存全部回收。

问题:解决了空间碎片,但只能使用一半的内存

标记-整理算法(适合老年代)

将存活对象移动到内存的一端,然后清除边界之外的所有内存。

【既不会产生空间碎片,也不会导致内存折半】

“因地制宜”——分代算法

分代算法,就是根据 JVM 内存的不同内存区域,采用不同的垃圾回收算法。

例如对于存活对象少的新生代区域,比较适合采用复制算法。这样只需要复制少量对象,便可完成垃圾回收,并且还不会有内存碎片。

而对于老年代这种存活对象多的区域,比较适合采用标记清除算法或标记整理算法,这样不需要移动太多的内存对象。

GC回收器

Serial 回收器

Serial回收器是一种单线程串行回收器,使用复制算法,在执行回收时会产生较长时间的停顿,优点是不会产生线程切换的开销

通过JVM参数-XX:+UseSerialGC可以使用串行垃圾回收器。

Serial Old 回收器

SO回收器是一种多线程并行回收器,使用标记整理算法,适用老年代

ParNew回收器

PN回收器是一种多线程并行器,使用复制算法。

参数控制:-XX:+UseParNewGC

Parallel Old回收器

PO是一种多线程回收器,使用标记整理算法,适用老年代

Parallel Scavenge回收器

PS回收器也是一种多线程并行回收器,使用复制算法,特点是可设置吞吐量

参数:-XX:+UseParallelGC

CMS收集器

CMS使用标记清除算法,主要目的是回收时的低停顿。

过程:

  • 初始标记:单线程(触发停顿),标记与GC Roots关联的对象
  • 并发标记:标记不可达对象(可能产生回收对象,所以之后需要重新标记)
  • 重新标记:单线程(触发停顿),纠正标记
  • 并发清除:清除对象

问题:

  • CPU资源消耗高
  • 浮动垃圾产生(回收时产生了新的垃圾)
  • 标记清除算法导致的空间碎片问题

G1回收器

特点:

  • 停顿时间:G1可充分利用多核多CPU的优势减少停顿时间,并且可建立可以预测的停顿模型,可设置停顿的时间
  • 支持分代回收,可使用分区策略同时兼顾老年代和年轻代
  • 使用标记整理算法,不会产生空间碎片

分区思路:

为什么使用分区:针对老年代的操作需要扫描所有的老年代空间;由于连续,必须分配年轻代和老年代的地址位置

G1之前的内存都是连续的:

GC回收算法&GC回收器_第1张图片

G1回收器的内存按区等分,分为eden,survivor,old和humongous:

GC回收算法&GC回收器_第2张图片

G1回收器回收流程:

  • 初始标记
  • 并发标记
  • 重新标记
  • 并发回收

Minor GC 和Full GC

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。

Full GC 是清理整个堆空间—包括年轻代和永久代。

Full GC执行条件:

  • 调用System.gc时,系统建议执行Full GC,但是不必然执行
  • 老年代空间不足
  • 方法区空间不足

你可能感兴趣的:(GC回收算法&GC回收器)