【问题标题】:Can virtual C# members be inlined?虚拟 C# 成员可以内联吗?
【发布时间】:2019-09-03 23:20:41
【问题描述】:

考虑以下替代实现,派生的内部类旨在覆盖,返回true

public virtual bool IsInternal => false;

...和...

public virtual bool IsInternal() => false;

内存和性能方面的区别是什么?

编译器能否检测静态结果并在优化/内联时使用它们而不是保存每个实例的属性值或调用函数? 编译器是否可以内联这些虚拟成员?会有什么影响?

【问题讨论】:

  • 你为什么要问?你的问题的背景是什么?为什么答案对你很重要?
  • 在您的两个解决方案中,第一个是只读属性(没有支持字段),第二个是函数。该属性(以您编写的样式)在引擎盖下基本上是相同的功能。所以我希望它们在大多数情况下表现基本相同。

标签: c# performance compiler-optimization


【解决方案1】:

内存和性能方面的区别是什么?

没有,它们都编译为虚拟方法(C# 属性只是 getter+setter 方法的不同语法)。

每个虚拟成员都会增加一个类型的 vtable 大小(不过这可以忽略不计,因为 vtable 是每个类型的,而不是每个实例的)。

在性能方面,虚拟调用会花费更多的指令,并且还需要更多的内存访问,但是具有现代分支预测和大型缓存的良好 CPU 可以最大限度地减少影响。如果您真的关心该级别的性能,那么您无论如何都不会使用 CLR - 就大多数开发人员而言,virtual 调用的成本与非虚拟调用相同。

编译器能否检测静态结果并在优化/内联时使用它们而不是保存每个实例的属性值或调用函数?

  • .NET Framework 1.0、1.1、2.0 和 4.0 中的 CLR 没有(据我所知)。 C# 编译器可能在某些微不足道的情况下(例如 (new BaseVirtualType().VirtualMethod()))将已编译 CIL 中的虚拟调用替换为非虚拟调用,但 JIT 不会进行该优化(但 JIT 然后可能内联它,但我不确定)。启用优化时,C# 编译器也可以内联。

  • 根据 .NET Core 3.0 的规范文档(见下文),.NET Core 2.0 中的 CLR 进行了一些去虚拟化。

  • .NET Core 3.0 中的 CLR 将更加激进,这里是继承者规范文档:https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/GuardedDevirtualization.md

【讨论】:

  • 只是为了澄清上述内容,C# 编译器从不内联任何内容。从 .Net Core 2.0 和 .Net Framework 4.7.2 开始,JIT 有时可以去虚拟化,如果成功,则内联。 Guarded Devirtualization 仍是一项实验性功能,未启用。我们可能会找到一种在 .Net 5 中启用它的方法——对此尚无定论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 2010-12-21
相关资源
最近更新 更多