首页 > 其他分享 >JVM——面试

JVM——面试

时间:2024-04-19 20:56:13浏览次数:35  
标签:标记 对象 Region 回收 面试 线程 垃圾 JVM

https://juejin.cn/post/6998527815964426271

https://juejin.cn/post/7101120209540349959

垃圾回收器

Serial(新生代)+ Serial Old(老年代)

特点:

  • 单线程垃圾回收器,垃圾回收过程中需要 STW,适用于运行在 Client 模式下的虚拟机;
  • 新生代标记复制算法,老年代标记整理算法。

img

ParNew(新生代)+ Serial Old(老年代)

特点:

  • Serial 的并行版本,新生代有多个垃圾回收线程进行回收;
  • 垃圾回收的并行是指多个垃圾回收线程同时操作,并发是指垃圾收集线程和用户线程同时执行。
  • 新生代标记复制,老年代标记整理。
  • 垃圾回收的并发是指垃圾回收线程和客户端线程交替执行;并行是指多条垃圾回收线程执行,用户线程处于等待状态。

img

Parallel Scavenge(新生代)

特点:

  • 重点关注吞吐量(高效率利用CPU,用户线程CPU时间/总CPU使用时间),而 CMS 重点关注停顿时间。
  • 新生代采用标记复制算法,老年代采用标记整理算法。

img

Serial Old(老年代)

img
Serial 的老年代版本,单线程。

Parallel Old(老年代)

Parallel Scavenge 的老年代版本,使用多线程和标记整理算法,重点关注吞吐量的场景可以使用 Parallel Scavenge + Parallel Old 垃圾收集器搭配使用。

img

CMS(老年代垃圾收集器)

特点:

  • CMS(Concurrent Mark Sweep)重点关注停顿时间。并且是第一款垃圾回收线程和用户线程基本上同时工作的垃圾回收器,在 GC 时不需要 STW。
  • 回收过程分为:
    • 初始标记:暂停所有线程,记录下与 GCRoots 相连的对象,速度很快;
    • 并发标记:同时开启 GC 和用户线程,用一个闭包去记录对象。但是在阶段结束时,不能保证记录了所有可达对象,因为用户线程还处于不断更新状态,所以 GC 线程无法保证可达性分析的实时性;
    • 重新标记:暂停所有线程,修正并发标记阶段因为用户程序运行导致标记变动的那部分对象;
    • 并发清除:同时开启用户线程和 GC 线程清理对象。

缺点:

  • 对 CPU 资源敏感,CMS 工作需要的垃圾回收线程数量=(处理器核数+3)/4,所以当核心数不足4个时,垃圾回收线程占总线程比例过大,CMS 回收时对用户程序影响就很大;
  • 无法处理浮动垃圾,最后并发收集阶段用户线程可能产生新的垃圾,而这部分垃圾无法回收必须等待下一轮回收才会被处理掉。浮动垃圾会占据空间,导致可使用内存变少。CMS不会像其它线程那样等待老年代完全占满后再收集,会在老年代占据 68% 左右空间时就开始回收。
  • 基于标记清除算法,会产生内存碎片YoungGC 时由于新生代存活的对象需要晋升到老年代,而老年代由于内存碎片问题导致放不下该对象,就会引发 FullGC

img

G1

https://www.cnblogs.com/hongdada/p/14579898.html

https://juejin.cn/post/7050324680875442183?searchId=20240418112735D8AD4AFC02F85174EE86#heading-20

G1 垃圾收集器不同于之前的收集器,它回收的是整个堆(新生代、老年代),其它收集器只会收集其中之一。并且G1 收集器提供了时间预测模型,用户可以通过配置 -XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200 来设置堆内存最大为 32g,设置 GC 最大停顿时间为 200ms。

在系统运行过程中,G1跟踪各个Region里的垃圾堆积价值大小(所获得空间大小以及回收所需时间),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region,从而保证了再有限时间内获得更高的收集效率。

内存结构

img

  • Region:

    G1 将内存划分为多个大小相等的 Region(默认2048份均分),而不是像其它垃圾收集那样划分为固定大小和数量的分代区域。其中每个 Region 都可以扮演 Edon、Survivor、Old 的角色。Region 大小可以通过 -XX:G1HeapRegionSize 参数指定,一般大小为 2^N(1M~32M)。

  • Humongous:

    巨型对象,大小超过了 Region 一半的对象,当线程为巨型分配空间时,不能简单地在 TLAB(每个线程可以独占地一个本地缓冲区空间)分配,因为巨型对象的移动成本高,一个分区可能容不下一个巨型对象。因此巨型对象会在老年代分配,所占用的空间为巨型分区。G1 内部做了优化,一旦没有发现引用指向巨型对象,则可直接在年轻代收集周期中被回收。

垃圾回收的优化

G1 收集器针对垃圾回收的优化包括:对引用对象的标记不需要扫描整堆,而是扫描记忆集;通过写屏障过滤掉不必要的操作,减少写栅栏的开销。

写屏障包括如下:

  • G1 垃圾回收时关注应用线程增加对黑色对象到白色对象的引用,当黑色对象新引用了白色对象时,便将这个黑色对象重新设置为灰(采用 pre-write barrier);
  • CMS 标记过程中关注线程删除了灰色对象到白色对象的引用,即出现灰色对象删除了白色对象的引用时,就将这个白色对象置为灰色。
  • 写屏障不是硬件层面的写屏障,而是软件层面的写屏障,可以理解为在引用赋值这个写操作之前加上一个切面,根据切点的加入时机不同又可以分为 pre-write barrierpost-write barrier
void oop_field_store(oop* field, oop new_value) {
  pre_write_barrier(field);             // pre-write barrier: for maintaining SATB invariant
  *field = new_value;                   // the actual store
  post_write_barrier(field, new_value); // post-write barrier: for tracking cross-region reference
}
  • 记忆集(RememberSet):在串行和并行垃圾回收器中,GC时是通过扫描整堆判断对象是否处于可达的路径中,G1为了避免扫描整个堆,采用记忆集记录所有其它 Region 对当前 Region 的引用情况( YGC 时只需要扫描 Rset 就可以确定 OldRegion 对 yonugRegion 的引用,不需要扫描全部 oldRegion;同理在 MixGC 时会扫描老年代 OldRegion,老年代也会持有一个 Rset(point-in 集合)来记录内部的引用情况)。
  • Rset写屏障:写屏障是指每次引用类型在执行写操作时,都会中断操作并执行一些额外的操作,以此过滤掉不必要的写操作。因为写栅栏的开销是很大的,G1 收集器的写屏障是和 Rset 相辅相成的,产生写屏障时会检查写入的引用指向的对象是否和当前引用在不同的 Region,不同的 Region 才通过卡表将相关引用指向对象所在 Region 对应的 Rset 中,通过过滤使 Rset 减少。
  • 卡表:如果线程修改了 Region 的内部引用,就必须要通知 Rset,更改其中的记录。但需要注意的是,如果引用的对象很多,赋值器就需要对每个引用做处理,赋值器的开销会很大。因此引入卡表,卡表将一个 Region 在逻辑上划分为若干个固定大小的连续区域,每个区域称之为卡片 Card。默认情况下每个 Card 都没有被引用,当一个地址空间被引用时,地址空间对应的数组索引值被标记为 “0”,Rset 会记录下这个数组的下标。卡表是对记忆集的一种实现。

img

img

CMS 中使用卡表的数据结构来标记老年代的某一块内存区域中的对象是否持有新生代对象的引用。JVM 将老年代的对象对应的卡页 CardPage 所在的位置标记为 dirty,这样在执行 YoungGC 时不需要扫描整个老年代对象,而是扫描卡表中被标记为 dirty 的内存区域。

特点:停顿预测模型

Pause Prediction Model 是停顿预测模型,与 CMS 不同的是用户可以设定整个 GC 过程的期望停顿时间,参数为 -XX:MaxGCPauseMillis 指定了 G1 垃圾收集过程目标停顿时间,默认为 200ms,但是它并不是硬性指标,而是期望值。

G1 垃圾回收过程

  • 对象分配
  1. 优先在 TLAB (线程本地缓冲区) 中分配,这样各个线程间不需要任何同步,提高了 GC 效率。但是当线程耗尽了自己的 Buffer 之后,需要申请新的 Buffer。这个时候依然会带来并发的问题。另外 TLAB 可能会有内存碎片的问题。
  2. TLAB 无法容纳,就在 Eden 区域分配,如果 Eden 无法分配就只能在老年代中分配;
  3. Humongous 区域分配,连续占用多个 Region的对象,如果发现没有引用指向巨型对象,就可以直接在年轻代收集周期中进行回收。
  • 垃圾回收

G1 的垃圾回收过程分为全局并发标记、混合垃圾收集两个步骤:

img

全局并发标记:

  1. 初始标记:标记处所有 GC Roots 节点以及直接可达的对象,需要 STW 但是时间很短;
  2. 并发标记:从 GC Roots 开始对堆对象进行可达性分析,该过程中可能对象间引用关系可能会变化,通过 SATB(snapshot at the begin)结合写前屏障记录下更新的引用对象信息。同时如果发现区域中所有对象都是垃圾会立刻回收;
  3. 重新标记:重新标记是为了修正并发期间引用发生变化的那部分对象;需要STW;
  4. 筛选回收:排序各个 Region 的价值和成本,根据用户期望制定回收计划,将回收收益较高的 Region 加入回收集中,清空记忆集并重置已经被清理的空的 Region;

拷贝存活对象:

  1. 将回收集中存活的对象复制到空的 Region 中,最后清空这些旧的 Region;

CMS 与 G1 对比

  • G1 垃圾回收器采用的是标记整理算法,因此空间是连续的;CMS采用的是标记清理,会出现内存碎片问题。因为是连续空间,G1 在分配内存时可以通过 CAS+指针碰撞 方式分配,CMS 只能采取空闲列表方式分配。
  • G1 以 Region 为基本单位进行回收,回收时优先进行 youngGC,然后等到老年代空间达到阈值,再次触发 youngGC,接着触发混合GC;
  • G1 垃圾回收没有固定时间,可能触发一次 GC 操作后只是完成了整个堆空间垃圾的标记和排序,在未来合适的时间触发垃圾收集。

img

ZGC

存储结构

ZGC 和 G1 一样采用了分区域的堆内存布局,不同的是 ZGC 的 Region 可以动态创建和销毁,容量也可以动态调整。

ZGC 的 Region 划分为以下三种:

  • 小型 Region,容量固定为 2MB;
  • 中型 Region,容量固定为 32MB;
  • 大型 Region,容量固定为 2MB的整数倍。

ZGC 为了省去卡表的维护操作,标记过程中会扫描全部 Region,如果判定某个 Region 中的存活对象需要被重分配,那么就将该 Region 放入重分配集中。

垃圾收集器搭配组合

img


YoungGC、MajorGC、FullGC

img

新生代分为 Eden、Survivor0、Survivor1,当垃圾回收后如果对象的年龄超过了 MaxTenuringThreshold 值,就晋升到老年代。

对象分配和转移

对象是如何在 Eden、Survivor0、Survivor1、Old Generation 之间进行分配和转移的呢?

  • 对象初始分配到 Eden 区域,当 Eden 区域无法容纳新对象时,触发一次 Young GC
    img

  • Young GC 过程中 Eden 区域仍然被引用的对象会被复制到 Survivor0 区域。而 Eden 区域未被引用的对象将被直接删除。经历过一次 YoungGC 后的对象的年龄+1。
    img

  • 下一次 YoungGC 时,会重复上述过程,不过这时候 Survivor0Survivor1 角色交换,交换的目的是将已经使用的 Survivor0 中仍然存活的对象复制到 Survivor1 中,然后清理剩余空间。
    img

  • 如此重复下去,直到新生代剩余存活对象能够执行晋升操作。此时存活对象从新生代的 From Survivor Space 晋升到老年代。
    img

  • 随着新生代不断有对象加入到老年代,老年代最终没有足够的空间容纳新晋升对象,此时触发 MajorGC
    img

GC 分类

https://www.zhihu.com/question/41922036

针对 HotSpot 虚拟机的 GC 类型,可以分为如下两大类:

  • PartialGC:并不收集整个 GC 堆的模式
    • YoungGC:只收集 Young Gen 的 GC;
    • OldGC:只收集 Old Gen 的 GC,只有 CMS 垃圾收集器拥有这个模式;
    • MixedGC:混合回收整个 YoungGen、部分 OldGen,只有 G1 垃圾收集器是这个模式;
  • FullGC:收集整个堆内存,包括 YoungGenOldGenPermGen 等所有部分的模式。

各种 GC 触发条件:

  • YoungGC:当 YoungGenEden 区域满时触发,注意 YoungGC 中有部分存活对象会晋升到 OldGen
  • FullGC:当准备触发一次 YoungGC 发现新生代中要晋升对象的总大小大于当前 OldGen 的空间,则不会触发 YoungGC 而是触发 FullGC。或者如果有 PermGen ,在 PermGen 没有足够空间时,触发一次 FullGC

类加载过程

https://blog.csdn.net/qq_38159458/article/details/105865964

https://zhuanlan.zhihu.com/p/268637051

标签:标记,对象,Region,回收,面试,线程,垃圾,JVM
From: https://www.cnblogs.com/istitches/p/18146764

相关文章

  • 2024-04-19 前端常见面试题汇总(js篇)
    以下是前端面试中关于JavaScript的一些常见问题及其答案,共包含超过50个问题:1.解释一下JavaScript中的变量提升(Hoisting)。变量提升是指在JavaScript中,变量和函数的声明会被提升到其所在作用域的最顶部。但需要注意,只有声明会被提升,赋值操作不会。2.解释一下JavaScript中的闭包(C......
  • 2024-04-19 前端常见面试题汇总(html篇)
    1、xhtml和html有什么区别?语法要求:XHTML要求严格的XML语法,例如所有标签必须小写,所有标签必须关闭(即使是空元素也要使用闭合标签),所有属性必须使用引号。HTML语法相对更宽松,不强制要求标签闭合,标签和属性的大小写不敏感。文件类型:XHTML文档必须以.xml、.xhtml或者.xhtml......
  • 【面试准备】【SQL】数据库有哪些约束?
    数据库中的约束(constraints)是用来确保数据库中数据的准确性和可靠性的一种规则。以下是一些常见的数据库约束:PRIMARYKEY(主键):确保列的值是唯一的,并且不能为NULL。FOREIGNKEY(外键):用于在两个表之间建立链接,并确保引用的数据的完整性。UNIQUE(唯一):确保所有列的组合在表中是......
  • 面试题:如何理解闭包
    之前看的闭包讲解,都是一些示例,不太好作为面试题作答内部函数如果引用了外部函数的变量,会形成闭包。如果这个内部函数作为外部函数的返回值,就会形成词法环境的引用闭环(循环应用),对应的变量就会常驻在内存中,形成大家所说的“闭包内存泄漏”。虽然闭包有内存上的问题,但是却突破了......
  • 【面试准备】跨域问题解决方法
    跨域是什么浏览器对于javascript的同源策略的限制,是一种安全策略举例:用户登陆某个网站后,服务器在客户端写了一些cookie,如果cookie被其他网站读取,那么隐私信息就会泄漏,包含用户的登录状态等。跨域情况说明:域名不同域名相同,端口不同二级域名不同跨域问题解决jsonpngi......
  • LeetCode 面试经典150题---008
    ####151.反转字符串中的单词给你一个字符串s,请你反转字符串中单词的顺序。单词是由非空格字符组成的字符串。s中使用至少一个空格将字符串中的单词分隔开。返回单词顺序颠倒且单词之间用单个空格连接的结果字符串。注意:输入字符串s中可能会存在前导空格、尾随空格......
  • 6.农芯科技面试
    1.SpringBoot注解我的回答:@SpringBootApplication,@EnableAutoConfiguration、RestController、@Mapper、@Repository、@Service、@Controller、@Autowired、@Resource标准回答:@SpringBootApplication包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan......
  • 前端面试题解析与总结
    在2024年的前端行业,面试是进入理想公司的一道门槛。不同公司的面试流程和考察点各有不同,下面将结合三家知名公司的面试题目进行分析和总结,为广大前端开发者提供一份参考指南。一、某对外电商一面:笔试题:弹窗组件防抖截流代码实现关系型数组转换成树形结构对象数组全排列......
  • 面试官:来说说vue3是怎么处理内置的v-for、v-model等指令?
    前言最近有粉丝找到我,说被面试官给问懵了。粉丝:面试官上来就问“一个vue文件是如何渲染成浏览器上面的真实DOM?”,当时还挺窃喜这题真简单。就简单说了一下先是编译成render函数、然后根据render函数生成虚拟DOM,最后就是根据虚拟DOM生成真实DOM。按照正常套路面试官接着会问vue......
  • 大数据面试题汇总
    大数据量场景面试题目录大数据量场景面试题假设有10亿手机号,如何快算判断一个手机号是否再其中?如何再海量数据中找到高频词?BitMap原理?BitMap应用?那么如何确定电话号码对应的是位图中的哪一位呢?假设有10亿手机号,如何快算判断一个手机号是否再其中?-无符号整数表示范围[0,1<......