Java 如何在内部维护函数 StackTrace

How does Java maintain function StackTrace internally

Java 如何生成线程的堆栈跟踪?

示例:

考虑 functionA 调用 functionB 调用 functionC 调用 functionD。如果在 functionD 中的任何一点使用 getStackTraceElementArray 它将给出 functionCalls 数组:

functionC->functionB->functionA

Java如何在运行时填充StackTraceElement数组?假设它到达被调用函数内部时填充调用函数,那么JVM如何在被调用方法内部获取调用方法的引用?

在最简单的情况下,堆栈跟踪是从...堆栈中获得的!
每个线程都有一个帧指针 (FP) 寄存器,指向当前堆栈帧的基地址。当一个Java方法被调用时,它首先创建一个新的栈帧,即将一堆信息压入栈中:

  • return 地址(调用方法的地方);
  • 当前 FP(指向调用者框架);
  • 被调用方法的方法ID;
  • 指向常量池缓存等的指针

然后它更新 FP 以指向新创建的框架。

这样,你看,帧指针构成了一个链表:如果我读取一个FP指向的值,我就得到前一帧的基地址。

现在请注意,对于每一帧,方法 ID 始终与 FP 具有相同的偏移量。所以堆栈遍历就像 while 循环一样简单(用伪代码编写):

address fp = currentThread.getFP();
while (fp != null) {
    methodID m = (methodID) read_stack_at(fp + METHOD_OFFSET);
    print_method(m);
    fp = (address) read_stack_at(fp);
}

这就是它在 JVM 中为解释方法工作的方式。编译方法有点复杂。它们通常不会在堆栈上保存方法引用。相反,有一个结构将编译代码的地址映射到包含编译方法信息的元数据。但是stack walking的思路还是一样的