当前位置: 首页 > 面试题库 >

抛出异常的哪一部分是昂贵的?

杨晟
2023-03-14
问题内容

在Java中,当实际上没有错误时使用throw /
catch作为逻辑的一部分通常是一个坏主意(部分),因为抛出和捕获异常的代价很高,并且在循环中多次执行通常比其他方法慢得多不涉及引发异常的控制结构。

我的问题是,是在throw / catch本身中还是在创建Exception对象时(因为它获得了大量的运行时信息,包括执行堆栈)而产生的成本?

换句话说,如果我这样做

Exception e = new Exception();

但是不要扔,是扔的大部分费用,还是扔+渔获物处理的成本很高?

我不是在问是否将代码放在try /
catch块中会增加执行该代码的成本,我是在问捕获Exception是昂贵的部分,还是创建(调用构造函数)Exception是昂贵的部分。

提出此问题的另一种方法是,如果我创建了一个Exception实例并一遍又一遍地抛出并捕获,那么这将比每次我抛出新的Exception都快得多吗?


问题答案:

创建
异常对象并不比创建其他常规对象贵。主要成本隐藏在本机fillInStackTrace方法中,本机方法遍历调用堆栈并收集所有必需的信息以构建堆栈跟踪:类,方法名称,行号等。

有关高异常成本的神话来自大多数Throwable构造函数都隐式调用的事实fillInStackTrace。但是,有一个构造函数可以创建Throwable没有堆栈跟踪的。它使您可以快速实例化可抛出对象。创建轻量级异常的另一种方法是重写fillInStackTrace

现在 抛出 异常怎么办?
实际上,这取决于在哪里 捕获 引发的异常。

如果使用相同的方法(或更确切地说,在相同的上下文中,因为上下文可以由于内联而包含多种方法)捕获它,则throw它的速度和简便性goto(当然,在JIT编译之后)也是如此。

但是,如果某个catch块位于堆栈的更深处,那么JVM需要展开堆栈帧,这可能需要更长的时间。如果synchronized涉及到块或方法,则花费的时间甚至更长,因为展开意味着释放已删除堆栈帧所拥有的监视器。

我可以通过适当的基准确认以上陈述,但是幸运的是,我不需要这样做,因为HotSpot的性能工程师Alexey
Shipilev的帖子已经很好地涵盖了所有方面:Lil’Exception
的出色性能。



 类似资料:
  • 问题内容: 我们知道捕获异常非常昂贵。但是,即使从不抛出异常,在Java中使用try-catch块是否也很昂贵? 问题答案: 几乎没有任何花销。代码的元数据不是在运行时进行设置,而是在编译时进行结构化,这样,当引发异常时,它现在执行相对昂贵的操作,即遍历堆栈并查看是否存在任何可捕获此异常的块。例外。从外行的角度来看,它可能也是自由的。它实际上是在抛出导致你付出代价的异常-但是,除非你抛出数百或数千

  • 问题内容: 考虑以下代码: 无需添加方法签名即可编译该代码。(它与同样表现到位,太)。 我理解为什么 可以 安全地运行它,因为实际上不能将其引发在块中,因此不能引发已检查的异常。我有兴趣知道在何处指定此行为。 并非永远都不会达到目标:以下代码也会编译: 但是,如果抛出一个检查的异常,它不会像我期望的那样编译: 在JLS Sec 11.2.2中 ,它说: 一,其抛出的表达式语句(§14.18)具有静

  • 是否有一种方法可以找出try块中的哪一行抛出异常? 问题 堆栈跟踪只在catch块中显示OtherException的行 删除try/catch块并不简单,因为有许多声明为抛出的异常,需要捕获这些异常才能编译代码。 感觉应该有一个简单的方法来做到这一点。 注意:这段代码不是我写的;-)

  • 抛出异常的行为是否可能抛出不同的异常? 为了抛出异常,必须(可选地)分配新对象,并调用其构造函数(隐式调用fillinstacktrace)。在某些情况下,听起来像addSupressed也被称为。那么如果没有足够的内存会发生什么呢?JVM是否需要预分配内置异常?例如,(1/0)会抛出OutOfMemoryError而不是ArithmeticException吗? 此外,构造函数是一个方法调用,因

  • 这个问题是针对Java和< code>CompletableFuture的。 如果我有一个像下面这样的异步方法, 如果步骤#1中的代码抛出,的调用者将在获得它返回的之前获得异常,而如果步骤#2中返回的中的代码抛出,调用者将仅在与返回的交互时获得异常。 这表明的调用方应该编写一些复杂的异常处理代码来处理这两种情况。 下面是另一个异步方法的示例,,该方法调用并返回它返回的字符串长度: 我的问题是: <