在日志记录系统中,每个日志输出都由辅助类完成,并使用诸如此类的方法
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;
}
这种运行成本有多高,是否会有显着的性能提升?
答案 0 :(得分:8)
是的,这个电话会有一些开销,但在所有可能的情况下,你会做这样的事情:
public static boolean DEBUG_ON = true; //change this before your production build
然后,
public void debug(String message){
if(DEBUG_ON){
//stack code here
}
}
这将导致您不接受真实代码中的点击。
即便如此,对于异常,您将在生成版本中抛出整个堆栈跟踪的Exception。
请注意,如果您正在使用一个像样的日志记录子系统,他们可能已经根据日志记录级别做了一些事情(在我们的日志系统中,取决于级别,debug()基本上是无操作)。 Log4j和其他人有不同的处理方式。
最后,我要说:不要担心它,直到它被证明是一个真正的性能问题。过早优化是所有邪恶的根源:)
答案 1 :(得分:7)
看起来获取当前线程(及其关联的ID)并不昂贵,但获取当前线程及其堆栈跟踪是。新的throwable()。getStackTrace()模式似乎比线程的堆栈跟踪模式快得多。
另外,请注意:此基准测试几乎没有堆栈深度,因为它只是一个主要方法,所以在服务器环境中,这种惩罚会更加沉重。
基准测试结果:
简单循环需要2毫秒
获取当前线程需要10毫秒
获取堆栈跟踪需要29564毫秒
获得可抛弃的堆栈跟踪耗时19910毫秒
<强>代码:强>
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");
答案 2 :(得分:4)
根据我的记忆,使用Thread.getStackTrace()
会产生一些影响 - 特别是对于大型堆栈(例如在服务器端或J2EE情况下使用时)。您可以尝试Throwable.getStackTrace()
以获得更好的效果。
无论如何,定期调用这些函数(而不是在异常情况下这样做)会影响您的应用。
答案 3 :(得分:4)
现在使用JDK 9&amp; 10,你可以使用StalkWalker,这不是一个昂贵的电话。
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());
}
});
}