全网最全JDK1~JDK15十一种JVM垃圾收集器的原理总结(下)

简介: 全网最全JDK1~JDK15十一种JVM垃圾收集器的原理总结(下)

12.png

CMS的缺点

吞吐量低

由于CMS在垃圾收集过程使用用户线程和GC线程并行执行,从而线程切换会有额外开销,因此CPU吞吐量就不如在GC过程中停止一切用户线程的方式来的高。

无法处理浮动垃圾,导致频繁Full GC

由于垃圾清除过程中,用户线程和GC线程并发执行,即用户线程仍在执行,则在执行过程中会产生垃圾,这些垃圾称为"浮动垃圾"。

如果CMS在垃圾清理过程中,用户线程需要在老年代中分配内存时发现空间不足,就需再次发起Full GC,而此时CMS正在进行清除工作,因此此时只能由Serial Old临时对老年代进行一次Full GC。

使用"标记-清除"算法产生碎片空间

由于CMS采用的是“标记-清除算法",因此产生大量的空间碎片,不利于空间利用率。为了解决这个问题,CMS可以通过配置

-XX:+UseCMSCompactAtFullCollection

强制JVM在FGC完成后対老年代进行压缩,执行一次空间碎片整理,但空间碎片整理阶段也会引发STW。为了减少STW次数,CMS还可以通过配置

-XX:+CMSFullGCsBeforeCompaction=n

在执行了n次FGC后,JVM再在老年代执行空间碎片整理。

在并发收集失败的情况下,Java虚拟机会使用其他两个压缩型垃圾回收器进行一次垃圾回收。由于G1的出现,CMS在Java 9中已被废弃。

三色标记算法 - 漏标问题引入

没有遍历到的 - 白色

自己标了,孩子也标了 - 黑色

自己标了,孩子还没标 - 灰色

第一种情况 ,已经标好了 ab,还没 d,如下,此时B=>D 消失,突然A=D了,因为 A已黑了,不会再 看他的孩子,于是 D 被漏标了!

12.png

13.png

14.png

漏标的解决方案

把 A 再标成灰色,看起来解决了?其实依然漏标!

CMS方案: Incremental Update的非常隐蔽的问题:

并发标记,依旧产生漏标!

15.png

16.png

于是产生了 G1!


G1(Garbage First)是一个横跨新生代和老年代的垃圾回收器。实际上,它已经打乱了前面所说的堆结构,直接将堆分成极其多个区域。每个区域都可以充当Eden区、Survivor区或者老年代中的一个。它采用的是标记-压缩算法,而且和CMS一样都能够在应用程序运行过程中并发地进行垃圾回收。


G1能够针对每个细分的区域来进行垃圾回收。在选择进行垃圾回收的区域时,它会优先回收死亡对象较多的区域。这也是G1名字的由来。


G1收集器(Garbage-First)

Hotspot 在JDK7中推出了新一代 G1 ( Garbage-First Garbage Collector )垃圾回收,通过

-XX:+UseG1GC

参数启用。和CMS相比,Gl具备压缩功能,能避免碎片向題,G1的暂停时间更加可控。性能总体还是非常不错的,G1是当今最前沿的垃圾收集器成果之一。

image.png

当今最前沿的垃圾收集器成果之一。

G1的特点

  • 追求停顿时间
  • 多线程GC
  • 面向服务端应用
  • 整体来看基于标记-整理和局部来看基于复制算法合并
    不会产生内存空间碎片.
  • 可对整个堆进行垃圾回收
  • 可预测的停顿时间

G1的内存模型

没有分代概念,而是将Java堆划分为一块块独立的大小相等的Region.当要进行垃圾收集时,首先估计每个Region中的垃圾数量,每次都从垃圾回收价值最大的Region开始回收,因此可以获得最大的回收效率.

image.png

G1将Java堆空间分割成了若干相同大小的区域,即region

包括

  • Eden
  • Survivor
  • Old
  • Humongous
  • 其中,Humongous是特殊的Old类型,专门放置大型对象.

这样的划分方式意味着不需要一个连续的内存空间管理对象.G1将空间分为多个区域,优先回收垃圾最多的区域.

G1采用的是Mark-Copy ,有非常好的空间整合能力,不会产生大量的空间碎片

G1的一大优势在于可预测的停顿时间,能够尽可能快地在指定时间内完成垃圾回收任务

在JDK11中,已经将G1设为默认垃圾回收器,通过jstat命令可以查看垃圾回收情况,在YGC时S0/S1并不会交换.

Remembered Set

一个对象和它内部所引用的对象可能不在同一个Region中,那么当垃圾回收时,是否需要扫描整个堆内存才能完整地进行一次可达性分析?

当然不是,每个Region都有一个Remembered Set,用于记录本区域中所有对象引用的对象所在的区域,从而在进行可达性分析时,只要在GC Roots中再加上Remembered Set即可防止对所有堆内存的遍历.

G1垃圾收集过程

初始标记

标记与GC Roots直接关联的对象,停止所有用户线程,只启动一条初始标记线程,这个过程很快。

并发标记

进行全面的可达性分析,开启一条并发标记线程与用户线程并行执行。这个过程比较长。

最终标记

标记出并发标记过程中用户线程新产生的垃圾,停止所有用户线程,并使用多条最终标记线程并行执行。

筛选回收

回收废弃的对象。此时也需要停止一切用户线程,并使用多条筛选回收线程并行执行。

image.png

S0/S1的功能由G1中的Survivor region来承载,通过GC日志可以观察到完整的垃圾回收过程如下,其中就有Survivor regions的区域从0个到1个

image.png

红色标识的为G1中的四种region,都处于Heap中.

G1执行时使用4个worker并发执行,在初始标记时,还是会触发STW,如第一步所示的Pause

回收算法

依旧前面例子:

image.png

image.png

因此,还是能追踪到 D,如果不维护 rset,需要扫描其他所有对象!因此只需要扫描该 region 即可~


针对新生代的垃圾回收器共有三个:Serial,Parallel Scavenge和Parallel New。这三个采用的都是标记-复制算法。其中,Serial是一个单线程的,Parallel New可以看成Serial的多线程版本。Parallel Scavenge和Parallel New类似,但更加注重吞吐率。此外,Parallel Scavenge不能与CMS一起使用。


针对老年代的垃圾回收器也有三个:刚刚提到的Serial Old和Parallel Old,以及CMS。Serial Old和Parallel Old都是标记-压缩算法。同样,前者是单线程的,而后者可以看成前者的多线程版本。


CMS采用的是标记-清除算法,并且是并发的。除了少数几个操作需要Stop-the-world之外,它可以在应用程序运行过程中进行垃圾回收。在并发收集失败的情况下,Java虚拟机会使用其他两个压缩型垃圾回收器进行一次垃圾回收。由于G1的出现,CMS在Java 9中已被废弃[3]。


G1(Garbage First)是一个横跨新生代和老年代的垃圾回收器。实际上,它已经打乱了前面所说的堆结构,直接将堆分成极其多个区域。每个区域都可以充当Eden区、Survivor区或者老年代中的一个。它采用的是标记-压缩算法,而且和CMS一样都能够在应用程序运行过程中并发地进行垃圾回收。


G1能够针对每个细分的区域来进行垃圾回收。在选择进行垃圾回收的区域时,它会优先回收死亡对象较多的区域。这也是G1名字的由来。


100g内存时,到头性能.

且G1 浪费空间,fullgc 特别慢!很多阶段都是 STW 的,所以有了 ZGC!

ZGC

听说你是 zerpo paused GC?

Java 11引入了ZGC,宣称暂停时间不超过10ms,支持 4TB,JDK13 到了 16TB!

和内存无关,TB 级也只停顿 1-10ms

image.png

UMA

image.png

  • NUMA
    知道NUMA存在并且能利用,哪个CPU要分配对象,优先分配离得近的内存
  • 目前不分代(将来可能分冷热对象)
    ZGC 学习 Asul 的商用C4收集器

颜色指针

image.png

原来的GC信息记录在哪里呢?对象头部

ZGC记录在指针,跟对象无关,因此可以immediate memory reuse

低42位指向对象,2^42=4T JDK13 2^44=16T, 目前最大就 16T,还能再大吗???

后面四位伐表对象不同状态m0 m1 remapped finalizable

18为unused

灵魂问题

内存中有个地址

地址中装了01001000 , mov 72,到底是一个立即数,还是一条指令?CPU->内存,通过总线连接,-> 数据总线地址总线控制总线,所以看是从啥总线来的即可

主板地址总线最宽 48bit 48-4 颜色位,就只剩 44 位了,所以最大 16T.


ZGC 阶段

1.pause mark start

2.concurrent mark

3.relocate

image.png

4.remap

对象的位置改变了,将其引用也改变过去 - 写屏障(与 JMM 的屏障不同,勿等同!)

而 ZGC 使用的读屏障!

GC的优势在哪里

  • 流行于现代的各大语言和平台
  • 效率和稳定性
  • 程序员不需要负责释放及销毁对象消除了不稳定性,延迟以及维护等几乎全部(普遍的)的可能
  • 保证了互操作性
  • 不需要与APIs之间交互的内存管理契约
  • 与不协调的库,框架,应用程序流畅地交互操作
目录
相关文章
|
1天前
|
Rust 安全 Java
JVM原理与实现——Synchronized关键字
在多线程Java程序中,`Synchronized`关键字用于确保线程安全。本文深入探讨其工作原理,通过分析字节码`monitorenter`和`monitorexit`,解释JVM如何实现同步机制。文章展示了`Synchronized`方法的编译结果,并详细解析了轻量锁和重度锁的实现过程,包括Mark Word的状态变化及CAS操作的应用。最后简要介绍了`ObjectMonitor::enter()`函数在获取重度锁时的作用。
JVM原理与实现——Synchronized关键字
|
4月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
27天前
|
Oracle 安全 Java
深入理解Java生态:JDK与JVM的区分与协作
Java作为一种广泛使用的编程语言,其生态中有两个核心组件:JDK(Java Development Kit)和JVM(Java Virtual Machine)。本文将深入探讨这两个组件的区别、联系以及它们在Java开发和运行中的作用。
68 1
|
27天前
|
Java 编译器 API
深入解析:JDK与JVM的区别及联系
在Java开发和运行环境中,JDK(Java Development Kit)和JVM(Java Virtual Machine)是两个核心概念,它们在Java程序的开发、编译和运行过程中扮演着不同的角色。本文将深入解析JDK与JVM的区别及其内在联系,为Java开发者提供清晰的技术干货。
29 1
|
2月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
2月前
|
缓存 Java 索引
查看并解析当前jdk的垃圾收集器
本文介绍了如何查看和解析当前JDK使用的垃圾收集器,通过在IDEA中配置JVM选项并运行示例代码来展示G1垃圾回收器的详细信息和命令行标志。
35 0
查看并解析当前jdk的垃圾收集器
|
2月前
|
前端开发 Java 应用服务中间件
JVM进阶调优系列(1)类加载器原理一文讲透
本文详细介绍了JVM类加载机制。首先解释了类加载器的概念及其工作原理,接着阐述了四种类型的类加载器:启动类加载器、扩展类加载器、应用类加载器及用户自定义类加载器。文中重点讲解了双亲委派机制,包括其优点和缺点,并探讨了打破这一机制的方法。最后,通过Tomcat的实际应用示例,展示了如何通过自定义类加载器打破双亲委派机制,实现应用间的隔离。
|
4月前
|
缓存 Java 编译器
JRE、JDK、JVM 和 JIT 之间的区别详解
【8月更文挑战第22天】
197 0
|
1月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
273 1
|
21天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。