JVM之历代垃圾收集器详解

简介: JVM之历代垃圾收集器详解

JVM之历代垃圾收集器讲解

总览

分类

一,采用分代理念的垃圾回收器:

1.年轻代:

Serial

PartNew

Parallel Scavenge

2.老年代:

CMS

Serial Old(MSC)

Parallel Old

二,不采用分代理念的垃圾回收器:

G1

ZGC

Shenandoah

可搭配使用的各个收集器之间关系图:

并行和并发

很多人经常把这两个搞混,当然笔者刚开始的时候也是傻傻分不清楚。其实只要记住并行说的是GC 线程之间的关系,而并发说的是GC和用户线程之间的关系。

并行:同一时间有多条这样的线程在协同工作,但是此时用户线程时等待状态

并发:同一时间GC和用户线程可以一起工作一起运行。因此程序依然能够响应用户线程的操作但是由于GC线程也占用了一部分系统资源,所以此时的用户线程处理的效率会下降

年轻代垃圾回收器

Serial收集器

特点

垃圾回收时需要STW,整个STW需要停止掉所有的用户线程来保证回收过程中引用关系不会发生变化。

但是并不是说垃圾回收的时候只会启用一个回收线程,更准确的描述应该是同一时间只允许一个垃圾回收线程工作,也就是不支持并行工作,多个GC线程之间串行工作。

优点

1.对于内存资源受限的机器来说比较友好:

由于回收时停止掉了所有的用户线程,因此他不必维护那些:用户线程和GC线程同时运行的时候在回收过程中为了保证引用关系发生变化的额外内存开销;比如上一篇文章说到的原始快照和增量更新。

2.而且由于GC线程不是并行的,所以没有线程之间的交互;对于处理器内核少(线程少)的机器来说,

第一点也就是线程串行执行一个线程完了之后才能执行下一个线程,而对于并行的来说其实本质上还是串行只不过各个线程间可以自由来回切换,所以需要对切换前后的资源进行额外的保存等等因此并发涉及到的这部分线程交互开销对于该款串行执行的GC线程时没有的

图示:

缺点

但是缺点也很明显:回收过程中停止掉所有用户线程,对用户肯定是不能容忍的

PartNew收集器

特点:

该款垃圾收集器和刚才讲的第一个Serial收集器其实最大的不同就是GC Thread可以并行的区别。

注意是并行,之后讲解的CMS才是可以实现GC Thread并发的收集器。

Parallel Scavenge收集器

特点

该款垃圾收集器同样和PartNew收集器一样,并行GC线程。只不过该款收集器重点是倾向于吞吐量

老年代垃圾回收器

Serial Old收集器

区别于Serial回收器只是回收算法的不同

Parallel Old收集器

Parallel Scavenge收集器的老年代版本,支持多线程并发收集。

组合

吞吐量优先垃圾回收器组合

新生代采用Parallel Scavenge收集器,老年代采用Parallel Old收集器

CMS收集器

全称:Concurrent Mark Sweep

特点

1.采用标记-清除算法实现

2.和Parallel 系列的收集器注重点不同:

Parallel 注重吞吐量
CMS注重STW的停顿时间

工作流程

1.初始标记

CMS inital mark

标记GC Roots直接关联的对象

需要STW

2.并发标记

CMS concurrent mark

根据上一步和GC Roots直接关联的对象进行遍历整个堆里面的对象图并进行标记,由于是并发的所以并不需要停顿用户线程,但是比较耗时因为遍历整个对象图。

3.重新标记

CMS remark

在并发标记期间由于和用户线程时并发的,所以这段期间用户线程可能更新了引用,所以需要进行一次修正(详见上一篇文章中讲到的增量更新

需要STW,STW停顿时间比初始标记时间长,但是并没有并发标记运行时间长

4.并发清除

清除删掉被标记为垃圾的对象,由于采用的是标记-清除算法,所以并不需要移动存活对象因此是可以并发的。(当内存碎片严重到不足以分配对象时其实还是需要进行标记-整理算法的,这个时候就会提前触发FullGC。)

注意:在并发阶段产生的**“浮动垃圾”**(并发时用户线程产生的垃圾),需要等到下一次垃圾回收才能进行清理;而且并发的时候需要预留一部分内存空间供用户线程使用,所以不能等到老年代完全用完在进行清理。JDK5的默认设置是当老年代使用了65%的空间就会触发GC。

G1 收集器

特点

思维方式的重大转变:

G1之前的收集器都是分代收集的思想,根据不同的代采用不同的GC:新生代(Minor GC),老年代(Major GC),整个JAVA堆(Full GC)。

但是GC是根据哪块内存中垃圾数量多回收效益最大来区分的,面向的是堆内存中的任意一块内存来组成回收集(Collection Set)进行回收。

实现

基于Region的堆内存布局来实现该回收过程。不再以固定大小及固定数量来划分分代区域,而是把连续的堆内存区域进行划分为各自独立大小相等的区域(Region),每一个Region都可以根据需要扮演新生代中的Enen空间,Survivor空间,或者老年代。收集器根据扮演不同角色的Region采用不同策略去处理。

Region中有一类特殊的Humongous区域,专门用来存储大对象。

G1认为一个对象的大小超过了一个Region空间的一半就认为该对象是大对象,如果超过了整个Region空间的超大对象将会被存放在连续的Humongous Region中,因此该区域一般会被作为老年代看待。

优点

1.建立可预测的停顿时间模型

由于采用的是Region,因此回收单元作为Region即每次回收都是Region大小的整数倍。

G1会跟踪Region区域里面垃圾堆,计算出价值(回收所获得的空间大小以及回收所需时间的经验值),接着在后台维护一个优先级列表,根据用户设置的允许停顿时间来进行回收价值最大的Region区域。也就是“Garbage First”

的由来。

2.内存碎片

整体上采用的是标记-整理,但是在两个Region中实际上还是采用的复制算法,所以不会出现内存碎片问题。

缺点

1.浪费额外内存来维护收集器工作

跨代引用避免全堆扫描之前说过是采用记忆集的方式来解决,在G1中也一样。

每个Region中都有自己的记忆集但是在G1中每个Region除了需要记录别的Region指向自己的指针,还需要标记这些指针分别在哪些卡页范围内。其实本质上说是哈希表,Key是别的Region的起始地址,Value是一个集合存储的元素是卡表的索引号。

因此实现起来比原有的记忆集要复杂,而且Region的数量比之前的分代数量要多得多,所以记忆集的维护占用了更高的内存

G1至少要耗费大约相当于JAVA堆容量的10%到20%来存储维持收集器正常工作

2.不仅用到写后屏障还用到了写前屏障

上一小点中已经讲到维护卡表是需要进行添加写后屏障来完成更新卡表的操作的,但是G1还用到了写前屏障:由于使用的是原始快照来保证可以进行并发标记的基础,对比与增量更新来说虽然能够减少最终标记的停顿时间,但是相比于收集器,这款收集器不仅采用了写前屏障也采用了写后屏障导致最终的效率降低

工作流程

与之前不同的是最后一处,这个步骤需要进行更新Region的统计数据,对所有的Region的回收价值和成本进行排序,然后根据用户设定的期望停顿时间进行决定选择哪几个Region构成回收集,然后将一部分的Region中存活对象复制到另外一个空的Region空间中,随后进行清理掉整个旧的Region空间。是不是复制算法(针对与Region来说),因为涉及对象移动,所以需要暂停用户线程

总结

到此,如果读者之前阅读过笔者之前的关于垃圾回收器讲解的文章,其实已经对现在大多数垃圾回收器机制和实现原理了解的差不多了,读者有兴趣可以自行去看Shenandoah收集器和ZGC收集器,本文不在叙述,主要确实文章内容优点太长了哈哈。

后面的文章将不在分析垃圾回收器的知识,但是还是会更新关于JVM的文章。



目录
相关文章
|
1月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
51 2
|
3月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
3月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
27 3
|
3月前
|
C# UED 开发者
WPF打印功能实现秘籍:从页面到纸张,带你玩转WPF打印技术大揭秘!
【8月更文挑战第31天】在WPF应用开发中,打印功能至关重要,不仅能提升用户体验,还增强了应用的实用性。本文介绍WPF打印的基础概念与实现方法,涵盖页面元素打印、打印机设置及打印预览。通过具体案例,展示了如何利用`PrintDialog`和`PrintDocument`控件添加打印支持,并使用`PrinterSettings`类进行配置,最后通过`PrintPreviewWindow`实现打印预览功能。
350 0
|
3月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
194 0
|
3月前
|
算法 Java 程序员
【JVM的秘密花园】揭秘垃圾收集器的神秘面纱!
【8月更文挑战第25天】在Java虚拟机(JVM)中,垃圾收集(GC)自动管理内存,回收未使用的对象以避免内存泄漏和性能下降。本文深入介绍了JVM中的GC算法,包括串行、并行、CMS及G1等类型及其工作原理。选择合适的GC策略至关重要:小型应用适合串行收集器;大型应用或多核CPU环境推荐并行收集器或CMS;需减少停顿时间时,CMS是好选择;G1适用于大堆且对停顿时间敏感的应用。理解这些能帮助开发者优化程序性能和稳定性。
37 0
|
3月前
|
算法 Java
JVM自动内存管理之垃圾收集器
这篇文章是关于Java虚拟机(JVM)自动内存管理中的垃圾收集器的详细介绍。
|
4月前
|
监控 算法 Java
深入理解Java虚拟机:垃圾收集机制的演变与最佳实践
【7月更文挑战第14天】本文将带领读者穿梭于JVM的心脏——垃圾收集器,探索其设计哲学、实现原理和性能调优。我们将从早期简单的收集算法出发,逐步深入到现代高效的垃圾收集策略,并分享一些实用的调优技巧,帮助开发者在编写和维护Java应用时做出明智的决策。
54 3
|
4月前
|
算法 Java
Java面试题:列举并解释JVM中常见的垃圾收集器,并比较它们的优缺点
Java面试题:列举并解释JVM中常见的垃圾收集器,并比较它们的优缺点
98 3
|
4月前
|
Java UED
Java面试题:描述JVM中垃圾收集的Stop-The-World现象及其影响
Java面试题:描述JVM中垃圾收集的Stop-The-World现象及其影响
52 1