前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官问我JVM的GC分代收集算法为什么这么设计

面试官问我JVM的GC分代收集算法为什么这么设计

作者头像
Java极客技术
发布2022-12-04 12:54:56
3580
发布2022-12-04 12:54:56
举报
文章被收录于专栏:Java极客技术

最近阿粉的小学妹,给阿粉留言,说面试官不按套路出牌,问JVM的相关知识的时候,不问有什么GC算法,而是问我为什么这么设计,让学妹很懵圈,阿粉就差给小学妹的脑壳敲破了,面试官这么问,只是考验你,知其然,知其所以然么?今天阿粉就来简单的说说这个。

JVM 的垃圾回收机制

我们先来说说这个回收机制的算法都有哪些,如图所示。

目前面试比较常问的垃圾回收算法就是这几种,我们分开来说,最后说说分代收集为什么选择不同的算法来实现。

标记清除算法 Mark-Sweep

我们都知道,标记清除算法,是垃圾回收算法当中算是最基础的算法了,因为标记算法就只有两个阶段,

阶段一 标记

阶段二 清除

标记的是什么内容呢?

标记的都是所有的需要被回收的对象,当执行到清除阶段的时候,就会直接把这些标记的对象给完整的清除掉。

如果是这样的话,那么就会出现了一个问题,大家看,如果灰色的是我们的内存空间,然后我们把需要把被回收的对象清除的话,我们不能保证这个被回收的对象,一定会是连续排在一起的,就比如所有需要被回收的对象,都排在最上面的内存空间中,这个是不太可能的,所以,执行完清除之后,这些未使用的内存空间,就成了一个不连续的内存空间。

标记清除算法,最大的弊端出现了,碎片化就非常的严重,如果有大对象想要存入,而内存中出现没有连续空间的话,那他就没有可用空间保存了。

为了解决碎片化严重的这种情况,就有了下面的这种垃圾回收算法。

复制算法(copying)

为了解决这个内存碎片化严重的问题,按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉。

实际上,这种方式大家看起来,有没有什么问题呢?解决了碎片化严重的情况,但是他把内存空间,直接划分成了相等的两块,如果我们目前需要被回收的对象比较少,存活的对象比较多的话,那么这种复制算法的效率,真的是有点低了。

那么有没有一个折中的呢?

这就出现了另外一个算法,

标记整理算法(Mark-Compact)

这种算法比较特殊了,标记阶段和 Mark-Sweep 算法相同,但是整理的时候,就不一样了,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。也就是,有可能是存活对象被移到左边,然后右边是需要被清理的对象,

这样既能保证了内存空间是连续的,而且还能让效率提升。

那么我们可以回归这个标题了,GC分代收集,为什么这么设计。

分代

这个就挺好理解的,毕竟都知道一个共同的知识点,那就是 GC堆内存分为了老年代和新生代。

如果要选择算法,那么一定得从他们的本质去入手。

老年代:存活数量多,需要被处理的对象少

新生代:存活数量少,需要被处理的对象多

这种从本质的区别就划分出来了,一个存活对象多,一个存活对象少,一个需要被清理的对象多,一个需要被清理的对象少。

复制算法因为每次复制的都是存活的对象,而新生代的存活对象都是比较少的,所以这个时候就可以采用复制算法来实现。

也就是说,新生代中划分出来的大Eden 区 和两个 Survivor区,每次使用的时候都是 Eden 区和其中的一块 Survivor 区,当进行回收时,将该两块空间中还存活的对象复制到另一块 Survivor 区中。

所以因为新生代的这种特性,所以使用复制算法。

而老年代因为每次只回收少量对象,因而采用 Mark-Compact 算法。

这就是为什么面试的时候,面试官会问你为什么GC分代收集时选择不同算法的原因。

JVM的垃圾收集器

一般面试很多都是执着于去问垃圾回收机制和算法,很少有涉及到JVM的垃圾收集器的,阿粉今天稍微科普一下这个小知识。

Serial 收集器(新生代)

最早的收集器

采用复制算法,暂停所有用户线程,

特点是简单高效并且是单线程,但是容易导致全局停顿,就是我们经常所说的 STW(全局暂停)。

STW:

全局停顿,Java 代码停止运行,native 代码继续运行,但不能与 JVM 进行交互

ParNew收集器(新生代)

实际上属于 Serial 收集器 的升级版,从单线程变成了多线程,算法一样,也是暂停所有用户线程。

主要用来搭配 CMS 收集器一起使用。

Parallel Scavenge收集器(新生代)

吞吐量收集器,这个收集器关注的是吞吐量

在 JVM 中有参数可以配置

  • -XX:MaxGCPauseMillis:控制最大的垃圾收集停顿时间
  • -XX:GCTimeRatio:设置吞吐量的大小,取值 0-100, 系统花费不超过 1/(1+n) 的时间用于垃圾收集

Serial Old 收集器(老年代)

老年代的收集器,采用标记-整理算法

CMS 收集器(老年代)

算法采用标记-清除算法实现,

一般这个面试问的可能比较多,因为它属于并发的收集器,因为它并不会像前面说的那些收集器一样,会直接导致所有用户线程停止,直到清除结束,而是在标记过程中会有短暂的停止。

而是先进行初始标记,然后进行并发标记,修正并发标记用以进行重新标记,最后进行并发清除。

G1 收集器

G1(Garbage-First)收集器将堆内存分割成不同的区域,然后并发的对其进行垃圾回收。G1收集器的设计目标是取代CMS收集器,它同CMS相比,不会产生大量内存碎片,并可以添加预测机制,用户可以指定期望停顿时间(可通过配置-XX:MaxGCPauseMills=n最大停顿时间)

收集演示图:

说这些,最重要的却是,如何选择合适的垃圾收集器

组合选择:

  • 单CPU或小内存,单机程序 -XX:+UseSerialGC
  • 多CPU,需要最大吞吐量,如后台计算型应用 -XX:+UseParallelGC或者 -XX:+UseParallelOldGC
  • 多CPU,追求低停顿时间,需快速响应如互联网应用 -XX:+UseConcMarkSweepGC -XX:+ParNewGC

以上就是阿粉给大家带来的关于面试中的JVM 的一些小小的知识点了,有兴趣的可以继续深入了解关于 JVM 的知识,这样大家就能保证在面试的时候被面试官换个问法就不会的情况了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java极客技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM 的垃圾回收机制
  • 分代
  • JVM的垃圾收集器
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档