.NET JIT是否优化嵌套的try / catch语句? [英] Does the .NET JIT optimize nested try/catch statements?

查看:225
本文介绍了.NET JIT是否优化嵌套的try / catch语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在考虑嵌套的try / catch语句,并开始考虑JIT可以在哪些条件下执行编译的IL的优化或简化。



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

  //嵌套的try / catch 
try
{
try
{
try
{
foo();
}
catch(ExceptionTypeA){}
}
catch(ExceptionTypeB){}
}
catch(ExceptionTypeC){}

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

假设在嵌套的try语句的堆栈帧中没有其他变量引用或函数调用,JIT可以断定堆栈帧可能会被折叠到线性示例吗?



现在下面的例子如何?

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

void Main()
{
尝试< ExceptionC>(Try< ExceptionB> (尝试< ExceptionA>(FOO)));
}

我不认为JIT有任何方式内联代表调用,所以这个例子不能减少到前一个。但是,与线性示例相比,在 foo() throwing ExceptionC 的情况下,此解决方案是否执行得更差?我怀疑从代理调用中删除堆栈帧的额外成本,即使框架中包含的额外数据很少。

解决方案

值得注意的是,在第一种情况下,只有当您在catch块内不执行任何操作时,它们才能在功能上相当。否则,请考虑:

  try 
{
foo();
}
catch(IOException)
{
throw new ArgumentException(); //泡泡到调用者
}
catch(ArgumentException)
{
Console.WriteLine(Caught);
}

vs

  try 
{
try
{
foo();
}
catch(IOException)
{
throw new ArgumentException(); //由其他处理程序捕获
}
}
catch(ArgumentException)
{
Console.WriteLine(Caught);
}

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



这让我们选择JIT对空的catch块执行优化 - 这是一个非常不鼓励的做法。我不希望JIT花时间尝试检测不良代码,并使其运行速度稍快一点 - 如果确实有任何性能差异,首先。


I've been thinking about nested try/catch statements and started to think about under which conditions, if any, the JIT can perform an optimization or simplification of the compiled IL.

To illustrate, consider the following functionally-equivalent representations of an exception handler.

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

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

Assuming there are no additional variable references or function calls within the stack frames of the nested try statement, can the JIT conclude that the stack frames may be collapsed to the linear example?

Now how about the following example?

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

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

I don't think there is any way for the JIT to inline the delegate invocations, so this example can't be reduced to the previous one. However in the event of foo() throwing ExceptionC, does this solution perform poorer when compared to the linear example? I suspect there is an extra cost to tear down the stack frames from the delegate invocations, even though the extra data contained in the frames is minimal.

解决方案

It's worth noting that in the first case they're only functionally equivalent when you're doing nothing within the catch block. Otherwise, consider this:

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");
}

Now in this case the difference is obvious, but if the catch block calls some arbitrary method, how is the JIT meant to know what might be thrown? Best to be cautious.

That leaves us with the option of the JIT performing optimisations for empty catch blocks - a practice which is strongly discouraged in the first place. I don't want the JIT to spend time trying to detect bad code and make it run very slightly faster - if indeed there's any performance difference in the first place.

这篇关于.NET JIT是否优化嵌套的try / catch语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆