首都高赛车免安装正式中文版
6.7G · 2025-10-10
以Math类为例,体会下图JVM内存模型
public class Math {
public static final int initData = 666;
public static User user = new User();
public int compute(int a, int b) {
return a + b;
}
}
JVM内存模型如下:
对象在堆内部挪动的过程其实是复制,原有区域对象还在,一般不直接清理。JVM内部清理过程只是将对象分配指针移动到区域的头位置即可:
Minor GC在根扫描过程中会记录所有被扫描到的对象引用(在年轻代这些引用很少,因为大部分都是垃圾对象不会扫描到),如果引用的对象被复制到新地址了,最后会一并更新引用指向新地址。
第一阶段:标记和复制
1. 从GC Root开始遍历所有可达对象
2. 将存活对象从Eden区和From Survivor区复制到To Survivor区或老年代
3. 在复制过程中,JVM会维护一个转发表(Forwarding Table)
第二阶段:引用更新
1. 遍历所有已知的引用位置(栈、方法区、其他堆对象)
2. 检查这些引用是否指向已移动的对象
3. 如果指向已移动对象,则根据转发表更新引用地址
转发表是JVM用来跟踪对象移动的关键数据结构:
需要更新引用的位置包括:
记忆集(Remembered Set):
并发更新:
// GC前的状态
Object obj1 = new Object(); // 地址:0x1000
Object obj2 = new Object(); // 地址:0x2000
obj1.field = obj2; // obj1引用obj2
// Minor GC过程中
// 1. obj1复制到新地址:0x3000
// 2. obj2复制到新地址:0x4000
// 3. 更新引用:obj1.field = 0x4000
// GC后的状态
// obj1现在在地址0x3000
// obj2现在在地址0x4000
// obj1.field正确指向0x4000
这种机制确保了在对象移动后,所有引用都能正确指向新的内存位置,保证了程序的正确性。
因此,这句话准确地描述了元空间作为方法区实现的本质特征:它改变了元数据的存储位置,从堆内存迁移到直接内存,从而解决了传统永久代的一些限制。