Java 如何生成线程的堆栈跟踪?
例子:
考虑 functionA
调用 functionB
调用 functionC
调用 functionD
。如果在 functionD
中的任何一点使用了 getStackTraceElementArray
,它将给出函数调用数组:
functionC->functionB->functionA
Java 在运行时如何填充StackTraceElement
数组?假设它到达被调用函数内部时填充调用函数,那么JVM如何在被调用方法内部获取调用方法的引用?
最佳答案
在最简单的情况下,堆栈跟踪是从...堆栈中获取的!
每个线程都有一个帧指针 (FP) 寄存器,指向当前堆栈帧的基地址。当一个 Java 方法被调用时,它首先创建一个新的栈帧,即将一堆信息压入栈中:
- 返回地址(调用方法的地方);
- 当前 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 中为解释方法工作的方式。编译方法有点复杂。它们通常不会在堆栈上保存方法引用。相反,有一个结构将编译代码的地址映射到包含编译方法信息的元数据。但是堆栈遍历的思想仍然是一样的。
关于java - Java内部如何维护函数StackTrace,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37290028/