java类调用过程-简述
让我们把你描述的过程按照真实的时间顺序和物理动作重新梳理一遍阶段一准备阶段仅首次ClassLoader 工作读取Person.class文件。链接与解析验证字节码。在堆中创建Person的类对象包含 vtable。解析常量池把符号引用sayHello名字变成直接引用方法入口地址索引。结果内存里准备好了等待执行。阶段二执行Person p new Person();分配内存在堆 (Heap)开辟一块空间给新对象假设地址0xHEAP_P。初始化设置对象头类型指针指向Person类对象。赋值引用在栈 (Stack)的main帧里局部变量p存入数值0xHEAP_P。注意此时没有 ClassLoader 参与也没有解析器。阶段三执行String result p.sayHello();核心时刻步骤 1查找目标地址多态的关键CPU 读取栈上p的值 (0xHEAP_P)。根据0xHEAP_P找到对象头拿到类型指针。顺着类型指针找到vtable虚方法表。在 vtable 里查到sayHello对应的机器码入口地址假设是0xCODE_SAY。注如果是热点代码JIT 优化后可能直接硬编码跳转跳过查表。步骤 2调用 (CALL)CPU 执行CALL 0xCODE_SAY。动作 A把下一条指令地址返回地址比如0xMAIN_NEXT压入栈。动作 BCPU 指令指针 (RIP) 跳转到0xCODE_SAY。此时ClassLoader 和解析器依然不在场只有 CPU 在执行二进制指令。步骤 3执行方法体CPU 在0xCODE_SAY处执行机器码。遇到return Hello。JVM 确保Hello对象存在可能在常量池也可能在堆。假设地址是0xHEAP_STR。关键动作把0xHEAP_STR写入RAX寄存器返回值专用。RAX寄存器是线程隔离要注意防止线程污染步骤 4返回 (RET)CPU 执行RET指令。动作从栈顶弹出之前存的0xMAIN_NEXT写入指令指针 (RIP)。注意这里不需要找 p不需要查 vtable只需要弹栈。步骤 5接收结果CPU 回到main方法的0xMAIN_NEXT位置继续执行。执行指令MOV [result_address], RAX。把RAX里的0xHEAP_STR复制到栈上result变量的位置。 总结一句话p.sayHello()的执行过程是在类已加载的前提下CPU 通过p的引用查表 (vtable)找到代码地址压栈后跳转执行将结果放入RAX寄存器最后通过RET弹栈回到原点将RAX的值抄写给result。