我一直在思考嵌套的try / catch语句,并开始考虑在什么条件下,如果有的话,JIT可以执行编译IL的优化或简化。

为了说明,考虑一个异常处理程序的以下功能上的等效表示。

// Nested try/catch
try
{
  try
  {
    try
    {
      foo();
    }
    catch(ExceptionTypeA) { }
  }
  catch(ExceptionTypeB) { }
}
catch(ExceptionTypeC) { }

// Linear try/catch
try
{
  foo();
}
catch(ExceptionTypeA) { }
catch(ExceptionTypeB) { }
catch(ExceptionTypeC) { }

假定没有额外的变量引用或嵌套try语句的堆栈帧中的函数调用,可以在JIT断定该堆栈帧可被折叠到线性示例

现在如何有关以下实例

void Try<TException>(Action action)
{
  try
  {
    action();
  }
  catch (TException) { }
}

void Main()
{
  Try<ExceptionC>(Try<ExceptionB>(Try<ExceptionA>(foo)));
}

我不认为有任何方式的JIT内联委托调用,所以该实施例中不能被减小到前一个。然而,在foo()投掷ExceptionC的情况下,也相对于线性例如,当该溶液进行较差?我怀疑有推倒从委托调用堆栈帧的额外成本,即使包含在帧中的额外数据是最小的。

有帮助吗?

解决方案

值得一提的是,他们是第一种情况下的只有的,当你在做的catch块中没有任何功能上等同。否则,考虑:

try
{
    foo();
}
catch (IOException)
{
    throw new ArgumentException(); // Bubbles up to caller
}
catch (ArgumentException)
{
    Console.WriteLine("Caught");
}

VS

try
{
    try
    {
        foo();
    }
    catch (IOException)
    {
        throw new ArgumentException(); // Caught by other handler
    }
}
catch (ArgumentException)
{
    Console.WriteLine("Caught");
}

现在在这种情况下,差别是显而易见的,但如果catch块调用一些任意的方法中,JIT是如何打算知道可能被抛出?最好要谨慎。

这给我们留下了执行空catch块的优化的JIT的选择 - 这是摆在首位强烈反对这种做法。我不希望JIT花时间试图检测恶意代码,使其非常稍快运行 - 如果确实有在首位任何性能差异

其他提示

我相对于性能的try / catch /最后区域的理解是这样的区域是透明的的代码的常规执行。也就是说,如果您的代码不抛出任何异常赶上,那么的try / catch /终于地区拥有的 ZERO 的对代码执行性能的影响。

然而,当将引发一个例外,运行时开始走起来从它上升时,检查元数据的表,以查看所涉及的网站是否包含内的任何临界try块的部位堆栈。如果找到一个(并且它具有一个合格的catch程序块或最后块),那么相关的处理程序被识别,并且执行分支到这一点。

升高和异常处理的方法,是从性能的角度昂贵。程序员不应该使用异常作为信令或控制在比特殊情况以外的任何其他节目流的方式(双关语意。)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top