在 HotSpot 中会生成一个填充对象来填满这一块,因为堆需要线性遍历,遍历的流程是通过对象头得知对象的大小,然后跳过这个大小就能找到下一个对象,所以不能有空洞。
当然也可以通过空闲链表等外部记录方式来实现遍历。
还有 TLAB 只能分配小对象,大的对象还是需要在共享的 eden 区分配。
所以总的来说 TLAB 是为了避免对象分配时的竞争而设计的。
那 PLAB 知道吗?可以看到和 TLAB 很像,PLAB 即 Promotion Local Allocation Buffers。
用在年轻代对象晋升到老年代时。
在多线程并行执行 YGC 时,可能有很多对象需要晋升到老年代,此时老年代的指针就“热”起来了,于是搞了个 PLAB。
先从老年代 freelist(空闲链表) 申请一块空间,然后在这一块空间中就可以通过指针加法(bump the pointer)来分配内存,这样对 freelist 竞争也少了,分配空间也快了。
大致就是上图这么个思想,每个线程先申请一块作为 PLAB ,然后在这一块内存里面分配晋升的对象。
这和 TLAB 的思想相似。
产生 concurrent mode failure 真正的原因《深入理解Java虚拟机》:由于CMS收集器无法处理“浮动垃圾”(FloatingGarbage),有可能出现“Con-current Mode Failure”失败进而导致另一次完全“Stop The World”的Full GC的产生。
这段话的意思是因为抛这个错而导致一次 Full GC。
而实际上是 Full GC 导致抛这个错,我们来看一下源码,版本是 openjdk-8。
首先搜一下这个错。
再找找看 report_concurrent_mode_interruption 被谁调用。
查到是在 void CMSCollector::acquire_control_and_collect(...) 这个方法中被调用的。
再来看看 first_state : CollectorState first_state = _collectorState;
看枚举已经很清楚了,就是在 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 搭配使用;