java 抛异常 性能_Java 进阶:异常影响性能吗?

[TOC]

Java 进阶:异常影响性能吗?

曾经在给一个业务系统增加限流功能,使用的限流组件在流量超过阈值时,会直接抛异常,异常导致 CPU 占用率飙升。第一次遇到这样的情况,让我们不得不思考,异常怎么会对性能造成这么大的影响?

下面我们写几个测试程序观察一下。

catch 中不做任何事情

public class ExceptionTest {

public static void main(String[] args) {

doExTest();

doExTest();

}

private static void doExTest() {

long start = System.nanoTime();

for (int i=0; i<100000; ++i) {

try {

throw new RuntimeException("" + Math.random());

} catch (Exception e) {

}

}

System.out.println("time: " + (System.nanoTime() - start));

}

}

测试结果如下:

time: 365218274

time: 224583244

第一次 doExTest 只是起到预热的作用,我们以第二次 doExTest 的时间为准。10 万次请求,平均每次请求耗时 2245 纳秒,也就是 0.002 毫秒,速度还是很快的。

catch 中输出异常到日志

public class ExceptionTest {

private static final Logger logger = LoggerFactory.getLogger(ExceptionTest.class);

public static void main(String[] args) {

doExTest();

doExTest();

}

private static void doExTest() {

long start = System.nanoTime();

for (int i=0; i<100000; ++i) {

try {

throw new RuntimeException("" + Math.random());

} catch (Exception e) {

logger.error("fuck", e);

}

}

System.out.println("time: " + (System.nanoTime() - start));

}

}

测试结果如下:

time: 13454674590

time: 9891780450

10 万次请求,平均每次请求耗时 98917 纳秒,大约 0.1 毫秒,比“不输出异常”的时候,慢了 50 倍。输出日志如此耗费性能,那么 logger.error 这一句做了什么事儿呢?

根据过滤规则,判断是否要输出日志

获取异常堆栈

拼接日志字符串,输出日志到文件

获取异常堆栈主要调用的如下方法,下面我们写程序,不输出日志到文件,测试只读取异常栈的性能:

public class Throwable implements Serializable {

public StackTraceElement[] getStackTrace() {

return getOurStackTrace().clone();

}

private synchronized StackTraceElement[] getOurStackTrace() {

// Initialize stack trace field with information from

// backtrace if this is the first call to this method

if (stackTrace == UNASSIGNED_STACK ||

(stackTrace == null && backtrace != null) /* Out of protocol state */) {

int depth = getStackTraceDepth();

stackTrace = new StackTraceElement[depth];

for (int i=0; i < depth; i++)

stackTrace[i] = getStackTraceElement(i);

} else if (stackTrace == null) {

return UNASSIGNED_STACK;

}

return stackTrace;

}

}

catch 中收集异常到字符串

public class ExceptionTest {

public static void main(String[] args) {

doExTest();

doExTest();

}

private static void doExTest() {

long start = System.nanoTime();

for (int i=0; i<100000; ++i) {

try {

throw new RuntimeException("" + Math.random());

} catch (Exception e) {

StackTraceElement[] stackTrace = e.getStackTrace();

}

}

System.out.println("time: " + (System.nanoTime() - start));

}

}

测试结果如下:

time: 1559107012

time: 795376775

10 万次请求,平均每次请求耗时 7953 纳秒,大约 0.008 毫秒,比“不输出异常”的时候,慢了 4 倍。这么看获取堆栈耗时并不多,耗时主要在输出日志到文件中。

总结

处理异常的几个步骤里,对性能的耗费从大到小依次为:输出到日志、获取异常堆栈、创建并 catch 异常。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值