1. JVM内存模型与跨代引用问题
在HotSpot虚拟机中,堆内存通常被划分为新生代(Young Generation)和老年代(Old Generation)。新生代又分为Eden区和两个Survivor区(From/To)。这种分代设计基于"弱代假说"(Weak Generational Hypothesis)——绝大多数对象都是朝生夕死的,存活时间长的对象会逐渐晋升到老年代。
跨代引用(Inter-generational Reference)指的是老年代对象持有对新生代对象的引用,或者新生代对象引用老年代对象。这种引用关系会导致一个关键问题:在进行Minor GC(只回收新生代)时,为了确定新生代对象是否存活,必须扫描整个老年代来确认引用关系,这显然会极大降低GC效率。
1.1 跨代引用的三种类型
- 老年代→新生代引用:这是最需要关注的类型,因为Minor GC时需要确定新生代对象的存活状态
- 新生代→老年代引用:对GC影响较小,因为老年代回收频率低
- 跨代循环引用:两个不同代的对象相互引用,这种情况较为少见但需要特殊处理
实际统计表明,在大多数Java应用中,老年代对新生代的引用只占老年代对象的1%-5%。为这少量引用扫描整个老年代显然不划算。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Card Table机制原理
Card Table是HotSpot解决跨代引用问题的核心数据结构,其核心思想是将老年代空间划分为固定大小的"卡片"(Card),通常每个卡片对应512字节的内存区域。通过维护这些卡片的脏标记(Dirty)来避免全量扫描。
2.1 数据结构实现
在JVM源码中(以OpenJDK为例),Card Table的相关定义如下:
cpp复制// hotspot/share/gc/shared/cardTable.hpp
class CardTable: public CHeapObj<mtGC> {
friend class VMStructs;
protected:
// 卡片大小,默认为512字节
static const int _card_shift = 9;
static const int _card_size = 1 << _card_shift;
//
