JVM垃圾回收

对象死亡

判断对象是否存活

垃圾:内存中已经不再被使用到的内存空间就是垃圾

引用计数器

给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的

  • 优点:实现简单、效率高

  • 缺点:不能解决对象之间循环引用的问题(因此该方法不可行)

循环引用就是:A引用B,B也引用A,但没别的对象引用这两个对象,这时其引用计数器不为0,所以引用计数器无法通知GC回收它们

可达性分析法

通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的

固定可作为 GC Root 的对象

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 在方法区中常量引用的对象,如字符串常量池中的引用
  • 本地方法栈中JNI(即一般说的native方法)引用的对象
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻异常对象,以及系统类加载器
  • 所有被同步锁(synchronized 关键字)修饰的对象

引用

强引用

如果一个对象具有强引用,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题

软引用

如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存

弱引用

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存

虚引用

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收

垃圾收集算法

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

首先标记出所有不需要回收的对象

在标记完成后统一回收掉所有没有被标记的对象

标记-复制算法

将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉

JVM实际实现中,是将内存分为一块较大的Eden区和两块较小的Survivor空间,每次使用Eden和一块Survivor,回收时,把存活的对象复制到另一块Survivor。HotSpot默认的Eden和Survivor比是8:1,每次能够使用90%新生代空间

  • 优点:实现简单,运行高效,不用考虑碎片
  • 缺点:内存有些浪费

标记-整理算法

标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存

分代收集算法

核心思想:根据对象存活周期的不同将内存分为几块,从而可以根据各个年代的特点选择合适的垃圾收集算法

如新生代通常采用复制算法,而老年代则采用标记-整理算法

垃圾收集器

垃圾收集器具体实现垃圾收集算法。HotSpot常见的收集算法及其作用邻域如下:

两个收集器之间存在连线,表示其可以搭配使用

Serial收集器

是一个单线程收集器,在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束

新生代采用标记-复制算法,老年代采用标记-整理算法

ParNew收集器

Serial 收集器的多线程并行版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和 Serial 收集器完全一样

新生代采用标记-复制算法,老年代采用标记-整理算法。

除了 Serial 收集器外,只有它能与 CMS 收集器配合工作

CMS

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用。

收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作

运行过程

使用的是标记-清除算法,其运行分为四个步骤:

  • 初始标记阶段:暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快
  • 并发标记阶段:同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。跟踪记录发生引用更新的地方
  • 重新标记阶段:修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录
  • 并发清除阶段:开启用户线程,同时 GC 线程开始对未标记的区域做清扫

优缺点

  • 优点:并发收集、低停顿
  • 缺点:对CPU资源敏感;无法处理浮动垃圾;由于使用标记-清除算法导致收集结束后会有大量空间碎片产生

G1

G1是一个分代的,增量的,并行与并发的标记-复制垃圾回收器。设计目标是为了适应现在不断扩大的内存和不断增加的处理器数量,进一步降低暂停时间(pause time),同时兼顾良好的吞吐量

被视为 JDK1.7 中 HotSpot 虚拟机的一个重要进化特征

特点

  • 可以面向堆内存任何部分来组成回收集(衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多)

  • 开创基于 Region 的堆内存布局,即将连续的Java堆划分为多个大小相等的独立区域(Region),每一个 Region 都能根据需要扮演新生代或老年代空间,从而采用不同的策略进行处理(还有一类特殊的 Region,Humongous,即一个对象的大小超过了某一个阈值——HotSpot中是Region的1/2,即标记为 Humongous)

  • G1 仍然保留新生代和老年代的概念,但新生代与老年代不再是固定的,都是一系列的动态集合(物理上不需要连续,逻辑上连续)

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,对老年代GC称为Major GC,而Full GC是对整个堆来说的

Minor GC:发生在Young space中的gc

Major GC:发生在老年代Tenured space中的gc

STW(stop the world):指的是用户线程在运行至安全点(safe point)或安全区域(safe region)之后,就自行挂起,进入暂停状态,对外的表现就是卡顿,而不论何种gc算法,不论是minor gc还是major gc都会STW,区别只在于STW的时间长短。
Full GC:无官方定义,通常意义上而言指的是一次特殊GC的行为描述,这次GC会回收整个堆的内存,包含老年代,新生代,metaspace等。

但是实际情况中,我们主要看的是gc.log日志,其中也会发现在部分gc日志头中也有Full GC字眼,此处表示含义是在这次GC的全过程中,都是STW的状态,也就是说在这次GC的全过程中所有用户线程都是处于暂停的状态

参考:

https://snailclimb.gitee.io/javaguide/#/docs/java/jvm/JVM%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6

https://blog.csdn.net/weixin_39309402/article/details/104756815

https://blog.csdn.net/qq_38384440/article/details/81710887 (什么时候会发生FullGC)

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2019-2021 子夜
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信