主题
高性能要求下异常对性能影响
对比方案
普通接入对比特殊处理:
- 默认实现异常
- 特殊处理
fillInStackTrace
方法
异常代码
NotFilledException.java
public class NotFilledException extends Exception { @Override public Throwable fillInStackTrace() { return this; } }
|
FilledException.java
public class FilledException extends Exception { }
|
JMH 测试代码
... @Fork(value = 3) @BenchmarkMode({Mode.Throughput}) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 8, time = 1) @Threads(value = 8) @State(Scope.Benchmark) public class FilledExceptionBenchmark { @Benchmark public void fill(Blackhole blackhole) { blackhole.consume(new FilledException()); }
@Benchmark public void notFill(Blackhole blackhole) { blackhole.consume(new NotFilledException()); } }
|
测试结果
Benchmark Mode Cnt Score Error Units fill thrpt 24 1709917.327 ± 30294.221 ops/s notFill thrpt 24 216433082.224 ± 17207092.730 ops/s
|
解读
public synchronized Throwable fillInStackTrace() { if (stackTrace != null || backtrace != null ) { fillInStackTrace(0); stackTrace = UNASSIGNED_STACK; } return this; }
private native Throwable fillInStackTrace(int dummy);
|
这是 Throw.java
代码内部实现。可以看到:
- 存在关键字
synchronized
,明显多线程下会有阻塞点。而且不是一个异常的问题,是所有异常,只要调用这个方法,都会阻塞。
- 存在关键字
native
,表明实际上是需要 JVM
将堆栈数据从 C++
层面上读取出来注入 Java
。这也是耗时操作。
- 处理异常是一个平衡,要在事后追查和性能间获得平衡。普通项目不用在意此事,高性能项目需要考虑这些问题。