引言:基于经典分代理论,虚拟机的堆内存可以划分成新生代,老年代。当虚拟机需要仅对新生代进行回收时(Minor GC),新生代中可能存在跨代引用,即老年代的对象中有指向新生代对象的引用。为此,正常情况下需要扫描整个老年代来确定哪些对象引用了新生代的对象,但这种方式的开销太大,所以JVM引入了记忆集的概念,采用记忆集的方式,能有效减小开销。
G1收集器出现之前的记忆集
首先,我们要了解记忆集(Rset)的概念,下面是ORACLE官方对于记忆集的解释
The data structure for keeping this information (old generation pointers to young generation objects), is a remembered set. A card table is a particular type of remembered set.
根据ORACLE官方的说法,记忆集是记录着从老年代向新生代引用的一种数据结构,Card Table是其中一种特殊的记忆集。在G1收集器出现之前,Card Table是解决跨代引用的实际方案。
如上图所示,把老年代划分成若干个卡页,而卡表是以字节为单位的数组,通过卡的索引index来对应卡页,每一个数组元素对应一个卡页,卡页的大小为512字节(HotSpot实现)。卡页中可能存在多个对象,但是只要当卡页中存在一个对象引用了新生代的对象,就将卡页对应的数组元素的值改为1,否则默认情况下是0值。
通过这种一一对应的关系,我们不用再扫描整个老年代,只要扫描卡表,就能够知道哪些卡页上面存在对象有跨代引用的,将这些卡页上面的所有对象加入GC Root扫描即可。
结语
(1)经典收集器指的是Serial+Serial Old ; ParNew+CMS ; Parallel + Parallel Old等基于经典分代理论实现的垃圾收集器。
(2)对于卡表的描述还有卡表和卡页的联系,ORACLE官网原文:
“Java HotSpot VM uses an array of bytes as a card table. Each byte is referred to as a card. A card corresponds to a range of addresses in the heap. Dirtying a card means changing the value of the byte to a dirty value; a dirty value might contain a new pointer from the old generation to the young generation in the address range covered by the card.”
(3)下一章我们将介绍实现利用写屏障技术来维护卡表