JVM-垃圾回收器概述

  • 垃圾回收器(Garbage Collectors)
  • 没有引用指向的对象就是垃圾

根搜索算法(ROOT Searching)

​ 在方法里面有一些局部变量,我们new出一个对象(根对象),这个对象会产生一些引用形成新的对象,新的对象也可能产生一些引用形成新对象。

​ 所以在运行时找到这个方法,只要能找到根对象就不是垃圾,找不到根对象的便是垃圾。

​ 什么是根?

​ 以下来自JVMS(Java虚拟机规范)

  • JVM stack : 虚拟机栈中引用的对象
  • native method stack : 本地方法栈中的对象
  • runtime constant pool : 运行时常量池
  • static references in method area : 静态引用的对象
  • clazz

回收算法

  • Mark-Sweep(标记压缩):
    • 将垃圾标记出来,直接清除掉。
    • 缺点:碎片化,会产生碎片,当分配大对象时可能会找不到空间
JVM-垃圾回收器概述_第1张图片
  • Copying (拷贝):
    • 将内存一分为二,只用一半
    • 缺点:会造成内存浪费
JVM-垃圾回收器概述_第2张图片
  • Mark-Compact(标记压缩):
    • 将垃圾标记出来后,再进行一个压缩。利于产生新对象
    • 缺点:效率低
JVM-垃圾回收器概述_第3张图片

垃圾回收器的发展路线

JVM-垃圾回收器概述_第4张图片
  • 随着内存越来越大的过程而演进

    • 从分代算法演化到不分代算法
    • 前六种:分代
    • G1:概念分代,物理上不分代
    • ZGC、Shenandoah:不分代
    • Epsilon:什么都不干
  • serial: 几十兆

  • Parallel:几个G

  • CMS:几十个G,承上启下,开始并发回收。采用三色标记。

    • 黑色:全部标记完
    • 灰色:自己标记完,成员变量,孩子没标记完
    • 白色:未标记
    • 三色标记一定会产生错标
  • G1:上百G,逻辑分代,物理不分代。采用三色标记,但使用SATB算法。解决了CMS中一定要进行重新标记的问题。

  • ZGC和Shenandoah:上T,逻辑和物理都不分代。采用ColoredPointers(颜色指针 着色指针)

  • Epsilon:啥也不干(调试,确认不用GC参与的程序)

    在早期,会将内存的堆空间分成两个不同的年代

JVM-垃圾回收器概述_第5张图片
  • 新生代,新new出来的对象

    • 年轻代又分为三块:
      • eden(伊甸)
      • 两块survivor(幸存者)
      • 由于对eden进行一次垃圾回收时会有八、九成的对象需要回收,所以当对eden进行垃圾回收的时候,只需要将不需要回收的对象复制到第一块survivor中,然后将整个eden进行垃圾回收。
      • 第二次对eden垃圾回收时,由于第一块survivor中可能也存在需要回收的垃圾,所以将eden和第一块survivor中不需要回收的对象复制到第二块survivor中,然后将eden和survivor中的全部对象进行回收。(YGC)
      • 之后的垃圾回收,只需要将两块survivor调换位置即可。而多次垃圾回收都没有清理掉的对象,会被存放到老年代中。
  • 老年代,经历过多次GC的顽固对象

    • 只有当老年代分配不下新对象时才会进行垃圾回收,多数时候在对老年代回收时也会对年轻代进行回收,所以也被叫做Full GC(FGC)

    • 不同垃圾回收器中,能进入老年代的对象的年龄不同

      • ps,po:15
      • CMS:6
      • G1:15

在不同的年代里采用不同的算法

  • 年轻代使用Copying算法
  • 老年代使用Mark Compact或者Sweep

​ 前六种分代的GC通常进行组合使用

  • Serial开头的是单线程
  • Parallel开头的是多线程
  • parNew:新一代的多线程
  • CMS:并发标记清楚
  • SerialOld:单线程工作在老年代
  • ParallelOld:多线程工作在老年代

Serial Young

a stop-the-world,copying collector which uses a single GC thread

(STW,使用拷贝算法的单线程回收器)

STW:使用垃圾回收器的时候,所有工作线程停止。

Serial Old

a stop-the-world, mark-sweep-compact collector which uses a single GC thread

(STW,使用标记清除或标记压缩算法的单线程回收器)

Parallel Scavenge

a stop-the-world,copying collector which uses multiple GC threads

(STW,使用拷贝算法的多线程回收器)

Parallel Old

a stop-the-world mark-sweep-compact collector which uses multiple GC threads

(STW,使用标记清除或标记压缩算法的多线程回收器)

CMS

先进行初始标记,初始标记会STW(相较于其他分代GC的STW时间更短,因为只找根对象),再进行并发标记,但并发标记会存在标记失误,所以会进行重新标记,重新标记时会STW,最后进行并发清理。

浮动垃圾:在标记过程中,对象被引用,而标记结束后,被停止引用而产生的垃圾。这次没回收掉,下一轮再回收。

parNew

a stop-the-world,copying collector which uses multiple GC threads

(STW,使用标记清除或标记压缩算法的多线程回收器)

与parallel Scavenge的不同点:可以和CMS组合工作

常用组合

  • Serial + Serial Old:已不常见
  • Parallel Scavenge + Parallel Old:JDK1.8中默认使用的PS+PO组合,称为Parallel GC
  • ParNew + CMS

G1

Garbage First

从G1开始不再分代,而是开始了分区(Region)清理。

ZGC和Shenandoah

两者都来源于C4。不需要进行调优,参数只有一个,号称没有任何STW。(但是贼贵)

ZGC是Oracle官方推出的,诞生于JDK11

Shenandoah是RedHat推出的,在JDK12中可以设置,主要跑在Open JDK

Epsilon

  • 作测试时使用,观察垃圾产生过程。
  • 不需要进行垃圾回收的程序使用

分代GC的路线

​ 在分代模型中,当我们new一个对象时,会优先在栈上分配。

​ 在栈上分配的对象不会涉及垃圾回收器,使用结束后自动弹出。

​ 如果不在栈上分配,会判断该对象大不大。

  • 如果大,则直接分配在Old(老年代)中,等待FGC。

  • 如果小,则分配在TLAB(线程本地分配缓存区,Thread Local Allocation Buffer),无论是否分配在TLAB中,最终都会分配到eden中。

    • 由于会造成线程同步,资源浪费,所以会为每个线程都分配一块专属的空间,这样不会产生线程竞争,效率高。

    伊甸区的对象经过GC清除后,如果清除掉就结束,没有清除掉进入s1(survivor),再经历GC后,如果仍未被清除掉,就判断年龄,年龄足够进入老年代,年龄不足进入s2。

    注:如何判断new出的对象大不大?

    • new出的对象大小超过了伊甸区
    • 伊甸区中已经存在对象,new出的新对象再伊甸区中放不下且大于伊甸区的一半
    • 通过参数指定
JVM-垃圾回收器概述_第6张图片

博主个人网站:我不爱你

你可能感兴趣的:(JVM-垃圾回收器概述)