为什么默认情况下不自动内联自动属性?

时间:2012-03-05 17:09:08

标签: c# compiler-construction inline jit

由于这些属性只是方法之下,可以理解的是,它们可能执行的任何逻辑的性能可能会或可能不会提高性能 - 因此可以理解为什么JIT需要检查方法是否值得内联。

然而,自动属性(据我所知)不能有任何逻辑,只需返回或设置基础字段的值。据我所知,自动属性由编译器和JIT处理,就像任何其他方法一样 (以下所有内容都依赖于上述段落正确的假设。)

值类型属性显示的行为与变量本身不同,但参考类型属性应该与直接访问基础变量具有完全相同的行为。

// Automatic Properties Example
public Object MyObj { get; private set; }

是否存在Reference Types的自动属性通过内联显示性能受损的情况?
如果没有,是什么阻止编译器或JIT自动内联它们?

注意:我知道性能增益可能是微不足道的,特别是当JIT很可能无论如何使用它时都会内联它们 - 但是增益可能很小,这似乎很简单的优化似乎是合乎逻辑的。无论如何介绍。

3 个答案:

答案 0 :(得分:5)

编辑:JIT编译器不能像你想象的那样工作,我想这就是为什么你可能不完全理解我试图在上面传达的内容。我在下面引用了你的评论:

  

这是一个不同的问题,但据我所知,只有在被调用足够次数的情况下,方法才会被检查为内联值。没有提到检查本身就是性能损失。 (让表演的大小与现在无关。)

首先,检查大多数(如果不是全部)方法以查看它们是否可以内联。其次,请记住,方法只会被JITed一次,并且在那一段时间内,JITer将确定是否会内联任何名为 in 的方法。这可能在您的程序执行任何代码之前发生。什么使被调用的方法成为内联的良好候选者?

x86 JIT编译器(x64和ia64不一定使用相同的优化技术)检查一些事情以确定方法是否适合内联,绝对不仅仅是它被调用的次数。 The article列出了如果内联将使代码变小,如果调用站点执行很多次(即在循环中),以及其他内容。每个方法都是自己优化的,因此该方法可以在一个调用方法中内联,而在另一个调用方法中不内联,如在循环的示例中。这些优化启发式只适用于JIT,C#编译器只是不知道:它产生的是IL,而不是本机代码。它们之间存在巨大的差异; native vs IL代码大小可能完全不同。

总而言之,出于性能原因,C#编译器没有内联属性。


jit编译器内联大多数简单属性,包括自动属性。您可以详细了解JIT如何决定内联方法调用at this interesting blog post

嗯,C#编译器根本没有内联任何方法。我认为这是因为CLR的设计方式。每个组件都设计为可在机器之间移动。很多时候,您可以更改.NET程序集的内部行为而无需重新编译所有代码,它可以只是替换(至少在类型没有更改时)。如果代码是内联的,它会破坏(伟大的,imo)设计,你会失去光彩。

让我们先谈谈C ++中的内联。 (完全披露,我有一段时间没有使用C ++全职,所以我可能会模糊,我的解释生锈,或完全不正确!我指望我的同伴SOers纠正并骂我)

C ++ inline keyword就像告诉编译器,“嘿,伙计,我希望你能够内联这个函数,因为我认为它会提高性能”。 Un 幸运的是,它只是告诉编译器你更喜欢它内联;它没有告诉它必须。

也许在较早的日期,当编译器的优化程度低于现在时,编译器通常会编译内联函数。然而,随着时间的推移和编译器变得越来越聪明,编译器编写者发现在大多数情况下,他们更擅长确定何时应该将开发人员的内联函数。对于那些没有的情况,开发人员可以使用seriouslybro_inlineme关键字(在VC ++中官方称为__forceinline)。

现在,为什么编译器编写者会这样做?好吧,内联函数并不总是意味着提高性能。虽然它确实可以,但如果使用不当,它也可以破坏您的程序性能。例如,我们都知道内联代码的一个副作用是增加代码大小,或“胖代码综合症”(免责声明:不是真正的术语)。为什么“胖码综合症”成了问题?如果你看看我上面链接的文章,它解释了,除其他外,内存很慢,代码越大,它在最快的CPU缓存(L1)中的可能性就越小。最终它只能适合内存,然后,内联没有做任何事情。但是,编译器知道这些情况何时会发生,并尽力防止它。

将它与你的问题放在一起,让我们这样看:C#编译器就像开发人员为JIT编译器编写代码:JIT更聪明(但不是天才)。它通常知道内联何时会有利于或损害执行速度。 “高级开发人员”C#编译器不知道如何内联方法调用可以使代码的运行时执行受益,所以它不会。我想这实际上意味着C#编译器很聪明,因为它将优化工作交给那些比它好的人,在本例中是JIT编译器。

答案 1 :(得分:4)

  

然而,自动属性(据我所知)不能有任何属性   逻辑,只需返回或设置基础字段的值。如   据我所知,自动属性由编译器处理   JIT就像任何其他方法一样。

自动属性不能具有任何逻辑是一个实现细节,对编译所需的那个事实没有任何特殊的知识。实际上,正如您所说的,自动属性被编译为方法调用。

假设自动propes是内联的,并且类和属性是在不同的程序集中定义的。这意味着如果属性实现发生更改,则必须重新编译应用程序才能看到该更改。这首先使用属性失败,这应该允许您更改内部实现,而无需重新编译使用的应用程序。

答案 2 :(得分:2)

自动属性就是 - 自动生成属性get / set方法。结果,IL对他们没什么特别的。 C#编译器本身非常small number of optimizations

至于为什么不内联的原因 - 想象你的类型是在一个单独的程序集中,因此你可以自由地更改该程序集的源代码,使其具有非常复杂的属性获取/设置。因此,编译器在根据您的类型创建新程序集时第一次看到自动属性时,无法推断get / set代码的复杂性。

正如您在问题中已经注意到的那样 - “特别是当JIT可能会内联它们时” - 这种属性方法可能会在JIT时间内联。