CLR如何优化属性引用?

时间:2017-03-20 20:55:38

标签: c# optimization clr cil

我很长时间以来一直是程序员,并且最近找到了编写C#的工作。我很想知道Visual Studio是否优化了对简单内存移动的属性调用,而不是执行函数调用和返回。所以我写了一个程序,它有两个版本的3D点类,有一个计算幅度的方法:一个版本直接访问字段,一个使用属性。我跑了100,000,000分,他们花了相同的时间。但是当我使用 ildasm 来查看生成的代码时,使用属性的版本似乎使用函数调用来访问属性值。 (这是发布版本,因此启用了代码优化。)

我的问题:

  1. 是否将get_X的函数调用优化为运行时的内存移动? (它似乎是这样,因为它需要与直接字段引用相同的执行时间。)

  2. 有没有办法,使用 ildasm 或其他工具,看看哪些优化在运行时发生?

  3. 我已尝试在没有调试器的情况下运行该过程,然后附加到该过程,但VS2017说“没有可用的反汇编”。

    直接调用私有字段的版本:

            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_XML);
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
            System.out.println(responseEntity);
    

    调用属性的版本,后跟.method public hidebysig instance float64 Abs() cil managed { // Code size 47 (0x2f) .maxstack 8 //000052: return Math.Sqrt(_x * _x + _y * _y + _z * _z); IL_0000: ldarg.0 IL_0001: ldfld float64 CPUTests.Point3d::_x IL_0006: ldarg.0 IL_0007: ldfld float64 CPUTests.Point3d::_x IL_000c: mul IL_000d: ldarg.0 IL_000e: ldfld float64 CPUTests.Point3d::_y IL_0013: ldarg.0 IL_0014: ldfld float64 CPUTests.Point3d::_y IL_0019: mul IL_001a: add IL_001b: ldarg.0 IL_001c: ldfld float64 CPUTests.Point3d::_z IL_0021: ldarg.0 IL_0022: ldfld float64 CPUTests.Point3d::_z IL_0027: mul IL_0028: add IL_0029: call float64 [mscorlib]System.Math::Sqrt(float64) IL_002e: ret } // end of method Point3d::Abs 方法:

    get_X

2 个答案:

答案 0 :(得分:4)

在调试时使用反汇编视图可能会显示属性getter和setter确实已内联。 您可以使用visual studio中的CTRL-ALT-D访问它。

如果要发现抖动优化,可以使用MethodImplOptions禁用它们。

public struct foo
    {
        private int _bar;
        public int bar
        {
            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
            get { return _bar; }
            [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
            set { _bar = value; }
        }
    }

会在调试时显示:

enter image description here

如果你没有放置属性,你甚至无法点击断点,因为所有的getter都已内联。

答案 1 :(得分:2)

杰弗里里希特在他的书“CLR通过C#”中写道:

  

对于简单的get和set访问器方法,即时(JIT)   编译器内联代码,以便没有运行时性能   由于使用属性而不是字段。

CLR通过C#是我的圣经,所以对我而言,这足以证明它们是内联的。

ildasm只能显示编译时发生的优化的最终结果。如果要检查运行时优化,则必须实际查看运行时代码,即从程序集生成并正在运行的代码。 S.O.S对WinDbg的扩展可能是一个可以帮助你的工具。