炸了!一口气问了我18个JVM问题! (2)

在 HotSpot 中会生成一个填充对象来填满这一块,因为堆需要线性遍历,遍历的流程是通过对象头得知对象的大小,然后跳过这个大小就能找到下一个对象,所以不能有空洞。

当然也可以通过空闲链表等外部记录方式来实现遍历。

还有 TLAB 只能分配小对象,大的对象还是需要在共享的 eden 区分配

所以总的来说 TLAB 是为了避免对象分配时的竞争而设计的。

那 PLAB 知道吗?

可以看到和 TLAB 很像,PLAB 即 Promotion Local Allocation Buffers。

用在年轻代对象晋升到老年代时。

在多线程并行执行 YGC 时,可能有很多对象需要晋升到老年代,此时老年代的指针就“热”起来了,于是搞了个 PLAB。

先从老年代 freelist(空闲链表) 申请一块空间,然后在这一块空间中就可以通过指针加法(bump the pointer)来分配内存,这样对 freelist 竞争也少了,分配空间也快了。

炸了!一口气问了我18个JVM问题!

大致就是上图这么个思想,每个线程先申请一块作为 PLAB ,然后在这一块内存里面分配晋升的对象。

这和 TLAB 的思想相似。

产生 concurrent mode failure 真正的原因

《深入理解Java虚拟机》:由于CMS收集器无法处理“浮动垃圾”(FloatingGarbage),有可能出现“Con-current Mode Failure”失败进而导致另一次完全“Stop The World”的Full GC的产生。

这段话的意思是因为抛这个错而导致一次 Full GC。

实际上是 Full GC 导致抛这个错,我们来看一下源码,版本是 openjdk-8。

首先搜一下这个错。

炸了!一口气问了我18个JVM问题!

再找找看 report_concurrent_mode_interruption 被谁调用。

查到是在 void CMSCollector::acquire_control_and_collect(...) 这个方法中被调用的。

炸了!一口气问了我18个JVM问题!

再来看看 first_state : CollectorState first_state = _collectorState;

炸了!一口气问了我18个JVM问题!

看枚举已经很清楚了,就是在 cms gc 还没结束的时候。

而 acquire_control_and_collect 这个方法是 cms 执行 foreground gc 的。

cms 分为 foreground gc 和 background gc。

foreground 其实就是 Full gc。

因此是 full gc 的时候 cms gc 还在进行中导致抛这个错

究其原因是因为分配速率太快导致堆不够用,回收不过来因此产生 full gc。

也有可能是发起 cms gc 设置的堆的阈值太高。

CMS GC 发生 concurrent mode failure 时的 full GC 为什么是单线程的?

以下的回答来自 R 大

因为没足够开发资源,偷懒了。就这么简单。没有任何技术上的问题。 大公司都自己内部做了优化。

所以最初怎么会偷这个懒的呢?多灾多难的CMS GC经历了多次动荡。它最初是作为Sun Labs的Exact VM的低延迟GC而设计实现的。

但 Exact VM在与 HotSpot VM争抢 Sun 的正牌 JVM 的内部斗争中失利,CMS GC 后来就作为 Exact VM 的技术遗产被移植到了 HotSpot VM上。

就在这个移植还在进行中的时候,Sun 已经开始略显疲态;到 CMS GC 完全移植到 HotSpot VM 的时候,Sun 已经处于快要不行的阶段了。

开发资源减少,开发人员流失,当时的 HotSpot VM 开发组能够做的事情并不多,只能挑重要的来做。而这个时候 Sun Labs 的另一个 GC 实现,Garbage-First GC(G1 GC)已经面世。

相比可能在长时间运行后受碎片化影响的 CMS,G1 会增量式的整理/压缩堆里的数据,避免受碎片化影响,因而被认为更具潜力。

于是当时本来就不多的开发资源,一部分还投给了把G1 GC产品化的项目上——结果也是进展缓慢。

毕竟只有一两个人在做。所以当时就没能有足够开发资源去打磨 CMS GC 的各种配套设施的细节,配套的备份 full GC 的并行化也就耽搁了下来。

但肯定会有同学抱有疑问:HotSpot VM不是已经有并行GC了么?而且还有好几个?

让我们来看看:

ParNew:并行的young gen GC,不负责收集old gen。

Parallel GC(ParallelScavenge):并行的young gen GC,与ParNew相似但不兼容;同样不负责收集old gen。

ParallelOld GC(PSCompact):并行的full GC,但与ParNew / CMS不兼容。

所以…就是这么一回事。

HotSpot VM 确实是已经有并行 GC 了,但两个是只负责在 young GC 时收集 young gen 的,这俩之中还只有 ParNew 能跟 CMS 搭配使用;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxpzg.html