面试官,不要再问我“Java 垃圾收集器”了

简介: 面试官,不要再问我“Java 垃圾收集器”了

如果Java虚拟机中标记清除算法、标记整理算法、复制算法、分代算法这些属于GC收集算法中的方法论,那么“GC收集器”则是这些方法论的具体实现。


在面试过程中这个深度的问题涉及的比较少,但对于理解上面的这些算法有很好的帮助。如果能够如数家珍,也是面试中的加分项,还是那句话,毕竟面试官的时间也不多了。


概念准备


在学习Java GC收集器之前,需要先了解一些内容和概念,首先如果没有学习《面试官,不要再问我“Java GC垃圾回收机制”了》的可先学习该篇文章,了解基本算法方法论。


下面了解几个概念以帮助后面的学习:线程暂停(Stop The World)、安全点(Safepoint)、安全区(Safe region)。


在执行可达性分析的时候会出现在分析的过程中对象关系引用等发生了变化,为了保证分析的准确性,就必须在分析的过程中暂停所有Java线程,Sun将这一事件称作“Stop The World”。


那么,什么时候暂停合适呢?并不是所有的时刻都可以暂停所有线程进行GC的,只有到达某些点才可以进行GC操作,这些点就称作安全点(Safepoint)。


安全点的设置不能太少,那样GC等待的时间就会太长,但也不能太多否则会增加运行时的负担。


所以,安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的。比如,循环的末尾、方法临返回前/调用方法的call指令后、可能抛异常的位置等。


HotSpot采用主动中断的方式,让执行线程在运行期轮询是否需要暂停的(GC设置的)标志,若需要则中断挂起。


对于正在运行的线程,可以主动运行到安全点并暂停执行,但是对于那些正在Sleep或阻塞的线程,当它们重新执行时可能已经过了安全点,但此时GC可能还没完成垃圾回收,这种情况该怎么办呢?


于是就有了安全区(Safe region)的概念,安全区是一块区域,在该区域中引用都不会被修改。比如,线程进入到安全区的时候先标识自己进入了安全区,等它被唤醒准备离开时,先检查GC是否完成,如果完成则可以离开,否则就在安全区等待。


了解了上面的基本概念之后,下面正式进入垃圾收集器的讲解。


垃圾收集器分类


先通过下图了解一下Hotspot的8种垃圾收集器及其应用。image.png两个收集器之间的连线,表示它们可以搭配使用。收集器所处的区域表示它是属于新生代收集器还是老年代收集器。其中ZGC为Java11引入的新的垃圾收集器。


默认垃圾收集器


不同Java版本采用的默认收集器如下。image.pngSerial收集器


Serial收集器是最基本、发展历史最悠久的收集器,是一个单线程的收集器。在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。就是所谓的“Stop The World。image.pngParNew收集器


ParNew收集器其实就是Serial收集器的多线程版本。除了使用多线程进行垃圾收集外,其余行为包括Serial收集器可用的所有控制参数、收集算法(复制算法)、Stop The World、对象分配规则、回收策略等与Serial收集器完全相同,两者共用了相当多的代码。image.pngParallel Scavenge收集器


Parallel Scavenge收集器是一个新生代搜集器,主要采用复制算法,与ParNew类似。但关注点与其他搜集器不同,目标是达到一个可控的吞吐量。


Serial Old收集器


Serial Old是Serial收集器的老年代版本,同样是一个单线程收集器,使用标记-整理算法。运作图同Serial搜集器。


Parallel Old收集器


Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。在JDK 1.6中才开始提供。image.pngCMS收集器


CMS(Concurrent Mark and Sweep 并发-标记-清除),是一种以获取最短回收停顿时间为目标的收集器。基于并发、使用标记清除算法,只针对老年代进行垃圾回收。


CMS收集器工作时,尽可能让GC线程和用户线程并发执行,以达到降低STW时间的目的。


整个操作步骤分为四步:初始标记(CMS initial mark)、并发标记(CMS concurrent mark)、重新标记(CMS remark)、并发清除(CMS concurrent sweep)。image.png在上图过程中,初始标记和重新标记都会触发“Stop The World”。


初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,在Java7中是单线程,在Java8以后可采用多线程。


并发标记阶段GC线程和应用线程并发执行,初始标记出来的存活对象,然后继续递归标记这些对象可达的对象。


重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。


优点:并发收集、低停顿。


缺点:对CPU资源非常敏感、无法处理浮动垃圾、标记-清除算法导致的空间碎片。


G1收集器


G1(Garbage-First)是一款面向服务端应用的垃圾收集器。支持新生代和老年代空间的垃圾收集。


该收集器可充分利用CPU和硬件缩短STW的时间,还具有“整合空间”、“可预测停顿”等特点。比如,可建立可预测的停顿时间模型,能让使用者明确指定在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。


使用G1收集器时,Java堆的内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔阂了,它们都是一部分(可以不连续)Region的集合。image.pngG1会跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的来由)。


G1收集器的运作大致可划分为以下几个步骤:初始标记(Initial Marking)、并发标记(Concurrent Marking)、最终标记(Final Marking)、筛选回收(Live Data Counting and Evacuation)。


整个流程来看,前几个步骤与CMS的流程很相似。同样的在初始标记和最终标记的过程中都会触发“Stop The World”。image.png其中,筛选回收阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。


ZGC收集器


ZGC(Z Garbage Collector),是一款可伸缩、低延迟、并发垃圾回收器。在Java11中引入,应用Linux64位系统。


其旨在实现以下几个目标:停顿时间不超过10ms、停顿时间不随heap大小或存活对象大小增大而增大、可以处理从几百兆到几T的内存大小。


ZGC将内存划分为多个区域,也称为ZPage。ZPages可以动态创建和销毁。它们也可以动态调整大小(与G1 GC不同),是2 MB的倍数。以下是堆区域的大小组:Small (2 MB)、Medium (32 MB)、Large (N * 2 MB)。


ZGC堆可以多次出现这些堆区域。中型和大型区域是连续分配的,如下图所示:image.png与其他GC不同,ZGC的物理堆区域可以映射到更大的堆地址空间(其中可以包括虚拟内存)。

image.pngZGC的执行过程包括:标记(初始标记、并发标记、边缘情况处理)、重新定位(查找重新定位块、根引用重新定位并更新、并发定位其他对象并存储新旧地址映射)、重新映射。


其中标记中的初始标记和边缘情况处理会引发“Stop The World”,重新定位中的“根引用重新定位并更新”也会引发“Stop The World”。


其中重新映射流程图如下:image.pngZGC打算以较短的应用程序暂停时间来支持大堆大小。为了实现此目标,它使用了包括彩色64位指针,负载屏障,重定位和重新映射的技术。


小结


本文介绍了场景的垃圾收集器以及相关的概念,属于较深层次的内容,针对这些内容还可以进一步进行横向或纵向拓展。


有朋友在评论区问,学这些有底层什么用?当然我们不仅仅是为了面试,就拿关于JVM结构及Java8 JVM内存结构变动来说吧。


昨天在部署一个比较大的项目时就出现“java.lang.OutOfMemoryError: Metaspace”异常,如果学习了之前的相关内容可以很轻易的定位到是因为JVM设置了Metaspace的上限参数,并且参数值设置小导致的。


目录
相关文章
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
算法 安全 Java
Java内存管理:深入理解垃圾收集器
在Java的世界里,内存管理是一块基石,它支撑着应用程序的稳定运行。本文将带你走进Java的垃圾收集器(GC),探索它是如何默默守护着我们的内存安全。我们将从垃圾收集的基本概念出发,逐步深入到不同垃圾收集器的工作机制,并通过实例分析它们在实际应用中的表现。文章不仅旨在提升你对Java内存管理的认识,更希望你能通过这些知识优化你的代码,让程序运行更加高效。
46 3
|
2月前
|
监控 算法 Java
Java内存管理:垃圾收集器的工作原理与调优实践
在Java的世界里,内存管理是一块神秘的领域。它像是一位默默无闻的守护者,确保程序顺畅运行而不被无用对象所困扰。本文将带你一探究竟,了解垃圾收集器如何在后台无声地工作,以及如何通过调优来提升系统性能。让我们一起走进Java内存管理的迷宫,寻找提高应用性能的秘诀。
|
2月前
|
Kubernetes Cloud Native Java
云原生之旅:从容器到微服务的演进之路Java 内存管理:垃圾收集器与性能调优
【8月更文挑战第30天】在数字化时代的浪潮中,企业如何乘风破浪?云原生技术提供了一个强有力的桨。本文将带你从容器技术的基石出发,探索微服务架构的奥秘,最终实现在云端自由翱翔的梦想。我们将一起见证代码如何转化为业务的翅膀,让你的应用在云海中高飞。
|
2月前
|
存储 算法 Java
解释 Java 堆空间和垃圾收集
【8月更文挑战第22天】
30 0
|
14天前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
35 2
|
1月前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
18天前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
21 0
|
2月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
2月前
|
Java
【Java基础面试三十七】、说一说Java的异常机制
这篇文章介绍了Java异常机制的三个主要方面:异常处理(使用try、catch、finally语句)、抛出异常(使用throw和throws关键字)、以及异常跟踪栈(异常传播和程序终止时的栈信息输出)。