【问题标题】:Escape analysis in the .NET CLR VM.NET CLR VM 中的逃逸分析
【发布时间】:2012-01-03 14:04:29
【问题描述】:

CLR 编译器/JIT 是否执行了任何转义分析?例如,在 Java 中,a loop variable 一个在循环中分配的对象似乎不会逃脱循环,而是分配在堆栈而不是堆上(请参阅Escape analysis in Java)。

为了澄清,在下面的示例中,编译器是否会优化 foo 的堆分配,因为它永远不会逃脱循环。

class Foo 
{ 
   int number;
   Foo(int number) { this.number = number; }
   public override string ToString() { return number.ToString(); }
}

for (int i = 0; i < 10000000; i++)
{
   Foo foo = new Foo(i);
   Console.WriteLine(foo.ToString());
}

【问题讨论】:

  • 通常,循环变量是一种值类型,它在堆栈上分配(在循环的情况下)。
  • 我的意思是在循环体内分配的变量。我将更新问题以澄清。
  • 你的意思是变量吗?还是对象? (概念上非常不同)
  • 您的ToString() 不正确;那应该是public override ToString() - 强调override
  • 是的,我指的是对象,而不是变量。我认为对问题的 Java 版本的引用会推断出这一点,但我应该使用正确的术语。你在ToString() 上一如既往地正确,我会修复代码...

标签: c# optimization clr jit escape-analysis


【解决方案1】:

如果您的意思是 object (new Foo(i);),那么我的理解是不:这永远不会在堆栈上分配;但是,它会在零代中死亡,因此收集起来非常有效。我不自称知道 CLI 的每个黑暗和潮湿的角落,但我不知道 C# 中 的任何场景会导致在堆栈上分配托管引用类型(例如stackalloc 不算数,而且非常具体)。显然,在 C++ 中您有更多选择,但它不是托管实例。

有趣的是,在 MonoTouch/AOT 上它可能会立即被收集,但这不是主要的 CLI 虚拟机(并且适用于非常特定的场景)。

至于 变量 - 通常在堆栈上(并在每次循环迭代中重复使用) - 但它可能不会强>。例如,如果这是一个“迭代器块”,那么所有未删除的局部变量实际上都是编译器生成的状态机上的字段。更常见的是,如果变量被“捕获”(到匿名方法或 lambda 表达式,两者都形成闭包),那么变量会被转换为编译器生成的捕获上下文中的字段, 每次循环迭代都是独立的(因为在循环内声明了foo)。这意味着每个在堆上都是独立的

至于i(循环变量)——如果那个被捕获,它会变得更有趣

  • 在 C# 1.2 中不存在捕获,但根据规范,循环变量是技术上每次迭代
  • 在 C# 2.0 到 4.0 中,循环变量是共享的(导致臭名昭著的 capture/foreach 常见问题)
  • 在 C# 5.0 及更高版本中,循环变量再次为每次迭代

这只会在变量被捕获时产生影响,但会改变它在捕获上下文中的确切表达方式的语义

【讨论】:

    【解决方案2】:

    值类型可能会分配在堆栈上(并非总是如此),但对于引用类型的实例则并非如此。事实上:

    特别是,引用类型实例的存储位置总是被视为长期存在的,即使它们被证明是短暂的。因此它们总是在堆上。

    (埃里克·利珀特:The Truth About Value Types

    The Stack Is An Implementation Detail 也是一个很好的阅读。

    【讨论】:

      【解决方案3】:

      虽然 x86 JIT 擅长“内联”值类型,但您的 sn-p 将不符合条件,因为 ToString 方法将是对装箱对象的虚拟调用。 编辑:情况可能并非如此,因为您没有覆盖ToString

      但是,从我的实验来看,x64 JIT 根本没有这样做。

      编辑:

      如果可能,请在 x86 和 x64 上测试您的代码。

      【讨论】:

      • Foo 是一个类,所以我不确定这有多少适用。
      猜你喜欢
      • 1970-01-01
      • 2015-06-10
      • 1970-01-01
      • 2022-01-10
      • 2019-07-04
      • 1970-01-01
      • 1970-01-01
      • 2014-11-20
      • 1970-01-01
      相关资源
      最近更新 更多