当Java抛出异常时,是否会生成堆栈跟踪?

14

假设我们不调用.printstacktrace方法-只是抛出和捕获异常。

我们正在考虑将其用于一些性能瓶颈。


4
如果您希望获得更好的性能,真的不应该抛出异常,这只应该用于那些不会影响性能的特殊情况。也许您可以在不使用异常的情况下完成您尝试做的事情? - Peter Lawrey
6个回答

19
不,堆栈跟踪是在异常对象构造时生成的,而不是在抛出异常时生成的。Throwable() 构造函数调用 fillInStackTrace()。(至少在Sun/Oracle JDK 6 for Windows中是这样)。

4
如果您关心性能,您可以重写fillInStackTrace()方法并使其不做任何操作。 - J-16 SDiZ
4
抛出异常和构造异常是有区别的。 - Andy Thomas
你是完全正确的,安迪。我没有仔细阅读问题。 - perp

9

当异常被构造时,会捕获堆栈跟踪信息。

如果您真的不关心堆栈跟踪信息,可以构造一个异常并多次抛出,但这看起来像是一种hack方法,可能会令人困惑。


4
一个 Throwable 对象会在被打印或不被打印时捕获当前的调用栈(使用本地代码)。这就是为什么异常不应该被滥用于控制流程的原因。

4

当调用printStackTrace()方法时,它不是懒惰构建的。

Neal Gafter(曾经是Java团队中Sun工程师)在这里提到了异常性能:

捕获异常堆栈跟踪时创建异常远比其他任何操作都要昂贵得多

此外,请参见这个问题


异常的代价很高,因为每次抛出异常时,都必须创建和填充堆栈跟踪。想象一下,进行余额转移操作,在1%的情况下由于资金不足而失败。 即使是这种相对较低的故障率,性能也可能受到严重影响。请在此处查看源代码和基准测试结果:http://www.jquantlib.org/index.php/Cost_of_Exceptions_in_Java - Richard Gomes

2
正如上面所回答的,当抛出异常时,并不会生成堆栈跟踪。相反,它们是在构造异常时生成的。我已经进行了下面的测试。 我认为这并不直观。发生问题的地方是抛出异常的地方,而不是构造异常的地方。
class ExceptionNewVsThrow {

    private static RuntimeException instantiateException() {
        return new RuntimeException("Hello");
    }

    private static void test1(Exception exception) throws Exception {
        throw exception;
    }
    
    public static void main(String[] args) throws Exception {
        Exception exception = instantiateException();
        test1(exception);
    }
}

输出结果如下:

Exception in thread "main" java.lang.RuntimeException: Hello
    at FSystem.experimental.exceptions.ExceptionNewVsThrow.instantiateException(ExceptionNewVsThrow.java:18)
    at FSystem.experimental.exceptions.ExceptionNewVsThrow.main(ExceptionNewVsThrow.java:26)

请注意堆栈跟踪中提到了 maininstantiateException,但没有提到 test1

0

提醒一下,你可以重载 fillInStackTrace 方法来避免性能损失。在 Twitter 中,我们会在某些不关心堆栈跟踪的异常中这样做。

Play 框架在 1.3.x 系列中也是这样做的。

此外,你还可以在构造函数中设置断点以查看 fillInStackTrace 的执行情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接