开发中,经常需要获取 Java 函数调用栈信息,无论是解决开发阶段的 Bug,还是记录日志用于分析线上问题,都非常有帮助。
单一线程的函数调用栈信息保存在一个 StackTraceElement 数组中,基于先进后出的栈结构,数组的第一个元素表示当前调用函数。
通过 StackTraceElement 这个类可以获取函数信息,如方法名、类名、行数等。其实在 Try Catch 异常捕获机制中,Exception 类提供的 printStackTrace
方法也是基于 StackTraceElement 数组操作的。
获取方法调用栈 StackTraceElement 数组有两种方式,借鉴 Throwable 异常机制,可以这样获取:
- (new Throwable()).getStackTrace()
还有一种方式就是利用当前线程。不同于堆,栈是属于线程的,而函数调用栈存储于栈中,那么自然可以通过从当前线程对象中拿到函数调用栈信息:
- Thread.currentThread().getStackTrace()
举个例子,简单测试:
|
|
运行一下,输出如下:
|
|
对应的栈结构如下:
函数调用栈 |
---|
method |
main |
线程中的某个函数被调用时,都会向当前线程的函数调用栈中压入一帧;调用完毕时,对应的这一帧便会被移出函数调用栈。
我们再修改一下测试代码,添加一个 testTwo 测试函数,并于 test 函数前调用:
|
|
运行一遍,打印的函数调用栈信息,除了行数上的变化,元素个数还是一样:
|
|
可以看到,并没有发现 testTwo 函数的信息,因为调用完毕出栈了。