对于Mirnor GC来讲它的耗时主要由两个因素决定:
复制活跃对象的时间
扫描card table(老年代对象引用新生代对象)的时间
标记
- gc root
- card table (https://www.ezlippi.com/blog/2018/01/jvm-card-table-turning.html)
经过统计信息显示,老年代持有新生代对象引用的情况不足1%,根据这一特性JVM引入了卡表(card table)来实现这一目的。如下图所示:
卡表的具体策略是将老年代的空间分成大小为512B的若干张卡(card)。卡表本身是单字节数组,数组中的每个元素对应着一张卡,当发生老年代引用新生代时,虚拟机将该卡对应的卡表元素设置为适当的值。如上图所示,卡表3被标记为脏(卡表还有另外的作用,标识并发标记阶段哪些块被修改过),之后Minor GC时通过扫描卡表就可以很快的识别哪些卡中存在老年代指向新生代的引用。这样虚拟机通过空间换时间的方式,避免了全堆扫描。
卡表的维护是通过使用写屏障实现的。