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的思路还是一样的
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的思路还是一样的