java Thread.getStackTrace() 有多贵?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2347828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How Expensive is Thread.getStackTrace()?
提问by Jaime Garcia
In a logging system, every log output is done by a helper class with a method such as this one
在日志系统中,每一个日志输出都是由一个辅助类完成的,它有一个这样的方法
public void debug(String message) {
Logger logger = Logger.getLogger(getCallingClass());
logger.debug(message);
}
...
public Class getCallingClass() {
/*
Calls Thread.getStackTrace() and back traces until the class on the stack trace
!= this.getClass().
*/
return classFound;
}
How expensive is this to run and could it have significant performance hits?
运行它的成本有多高,它是否会对性能产生重大影响?
采纳答案by Kylar
Yes, there is some overhead to this call, but in all likelyhood, you're going to do something like this:
是的,这个调用有一些开销,但很有可能,你会做这样的事情:
public static boolean DEBUG_ON = true; //change this before your production build
then,
然后,
public void debug(String message){
if(DEBUG_ON){
//stack code here
}
}
Which will cause you to not take the hit in your real code.
这将导致您不会在实际代码中受到影响。
Even then, for exceptions, you're going to throw a whole stack traced Exception in your production build.
即便如此,对于异常,您将在生产构建中抛出一个完整的堆栈跟踪异常。
Note that if you are using a decent logging subsystem, they will probably already do something based on the logging level (in our log system, depending on the level, debug() is basically a no-op). Log4j and others have different ways of handling this.
请注意,如果您使用的是不错的日志子系统,它们可能已经根据日志级别执行某些操作(在我们的日志系统中,根据级别,debug() 基本上是无操作的)。Log4j 和其他人有不同的处理方式。
Lastly, I'd say: Don't worry about it until it proves to be a real performance problem. Premature Optimization is the root of all evil :)
最后,我想说:在它被证明是一个真正的性能问题之前不要担心它。过早优化是万恶之源:)
回答by Ilya
It looks like getting the current thread (and its associated ID) is not expensive, but getting the current thread and its stack trace is. The new throwable().getStackTrace() pattern seems to be a lot faster than the thread's stack trace pattern.
看起来获取当前线程(及其关联的 ID)并不昂贵,但获取当前线程及其堆栈跟踪却很昂贵。新的 throwable().getStackTrace() 模式似乎比线程的堆栈跟踪模式快得多。
Also, note: this benchmark has almost no stack depth since its just a main method, so in a server environment this penalty will be a lot heavier.
另外,请注意:这个基准测试几乎没有堆栈深度,因为它只是一个主要方法,所以在服务器环境中这个惩罚会更重。
Benchmark results:
基准测试结果:
Simple loop took 2 ms
简单循环耗时 2 毫秒
Getting current thread took 10 ms
获取当前线程需要 10 毫秒
Getting stack trace took 29564 ms
获取堆栈跟踪需要 29564 毫秒
Getting throwable stack trace took 19910 ms
获取可抛出的堆栈跟踪需要 19910 毫秒
Code:
代码:
int trials = 10_000_000;
long start = System.currentTimeMillis();
long a = 1;
for (int i = 0; i < trials; i += 1) {
a += 1;
}
long duration = System.currentTimeMillis() - start;
System.out.println("Simple loop took " + duration + " ms");
start = System.currentTimeMillis();
a = 1;
for (int i = 0; i < trials; i += 1) {
a += 1;
Thread.currentThread().getId();
}
duration = System.currentTimeMillis() - start;
System.out.println("Getting current thread took " + duration + " ms");
start = System.currentTimeMillis();
a = 1;
for (int i = 0; i < trials; i += 1) {
a += 1;
Thread.currentThread().getStackTrace();
}
duration = System.currentTimeMillis() - start;
System.out.println("Getting stack trace took " + duration + " ms");
start = System.currentTimeMillis();
a = 1;
for (int i = 0; i < trials; i += 1) {
a += 1;
(new Throwable()).getStackTrace();
}
duration = System.currentTimeMillis() - start;
System.out.println("Getting throwable stack trace took " + duration + " ms");
回答by user3892260
Now with JDK 9 & 10, you can use StackWalker, which is not an expensive call.
现在使用 JDK 9 和 10,您可以使用 StackWalker,这不是一个昂贵的调用。
private void invoke006() {
var stack = StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES).walk((s) -> s.collect(Collectors.toList()));
stack.forEach(stackFrame -> {
if (stackFrame.getMethodName().equals("masterInvoker")) {
System.err.println("master called !!");
System.err.println(StackWalker.getInstance().walk((s) -> s.collect(Collectors.toList())).get(0).getMethodName() + ", line: " + StackWalker.getInstance().walk((s) -> s.collect(Collectors.toList())).get(0).getLineNumber());
}
});
}
回答by Traveling Tech Guy
From what I recall, there's some impact in using Thread.getStackTrace()- especially with large stacks (such as when using in server-side or J2EE situations). You could try Throwable.getStackTrace()for better performance.
据我所知,使用会产生一些影响Thread.getStackTrace()- 特别是对于大型堆栈(例如在服务器端或 J2EE 情况下使用时)。您可以尝试Throwable.getStackTrace()获得更好的性能。
At any rate, calling those functions regularly (as opposed to doing so in an exception situation) will impact your app.
无论如何,定期调用这些函数(而不是在异常情况下这样做)会影响您的应用程序。

