Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 局部字符串变量的实例化是否会影响性能?_C#_String_Performance_Initialization_Il - Fatal编程技术网

C# 局部字符串变量的实例化是否会影响性能?

C# 局部字符串变量的实例化是否会影响性能?,c#,string,performance,initialization,il,C#,String,Performance,Initialization,Il,我有两种情况: static void CreateCopyOfString() { string s = "Hello"; ProcessString(s); } 及 这两种情况下的IL如下所示: .method private hidebysig static void CreateCopyOfString() cil managed { // Code size 15 (0xf)

我有两种情况:

    static void CreateCopyOfString()
    {
        string s = "Hello";
        ProcessString(s);
    }

这两种情况下的IL如下所示:

    .method private hidebysig static void  CreateCopyOfString() cil managed
    {
        // Code size       15 (0xf)
        .maxstack  1
        .locals init ([0] string s)
        IL_0000:  nop
        IL_0001:  ldstr      "Hello"
        IL_0006:  stloc.0
        IL_0007:  ldloc.0
        IL_0008:  call       void ConsoleApplication1.Program::ProcessString(string)
        IL_000d:  nop
        IL_000e:  ret
    } // end of method Program::CreateCopyOfString

在第一种情况下,对
stringinit
stloc.0
ldloc.0
有额外的调用。 这是否意味着第一种情况的性能比第二种情况弱,在第二种情况下,字符串直接传递给方法,而不是首先将其存储在局部变量中


我看到了这个问题,但它似乎与我需要知道的有点不同。谢谢。

你看到的是未优化的IL,一方面,因此所有的“nop”。您可能会发现,在构建发布版本时,它会生成不同的代码

即使使用未优化的版本,如果您在优化JIT下运行,我也希望它最终使用相同的JIT代码

即使使用非优化的JIT,每次调用它时确实会生成做更多工作的代码,我也会错愕地看到这在任何实际应用程序中都会产生重大影响

一如既往:

  • 在开始之前设定绩效目标,并根据目标进行衡量
  • 找出哪些决策在以后的性能方面很难修正,并且担心这些决策远比像这样的决策更重要,这样的决策可以在以后更改,而不会对其他地方产生影响
  • 首先编写最简单、可读性最强的代码
  • 如果这样做的效果不够好,那么就调查一下,做出损害可读性的更改是否有助于提高性能,从而使痛苦得到保证

不,这不会影响性能。 您可以通过验证为这两者生成的机器代码是否相同来确认这一点。 注意,在优化的JIT中,ProcessString可能是内联的。为了避免这种情况,您可以添加
[MethodImpl(methodimpoptions.noinline)]
。 编译优化(发布)版本

  • 在WinDbg中打开可执行文件。根据您的EXE使用匹配的32位或64位版本
  • 键入
    sxe ld clrjit
    以在加载clrjit.dll时中断。键入
    g
    继续,直到中断
  • 通过
    加载SOS。通过SOS clr加载。请注意,对于早期的CLR版本,您需要使用mscorwks而不是CLR
  • 使用
    查找方法表的地址!名称2ee*
  • 键入
    !dumpmt-md
    以转储方法详细信息。请注意,此时CreateCopyOfString和DoNotCreateCopyOfString尚未JIT
  • 键入
    !bpmd.createCopyOfsString
    !bpmd.DonotCreateCopyOfsString
    在调用方法时中断。键入
    g
    继续。也可以使用
    !bpmd-md
    设置断点
  • 当遇到断点时,键入
    !u
    转储方法的机器代码
  • 请注意,当我尝试此方法时,只有一个方法是JIT的,可能是因为运行时确定这两个方法是相同的,而没有必要对另一个方法进行JIT。因此,我对调用进行了适当的注释,并重复注释以获取机器代码

    实际寄存器和地址会有所不同,但这两种方法都会产生以下机器代码:

    sub     rsp,28h
    mov     rcx,121E3258h
    mov     rcx,qword ptr [rcx]
    call    000007fe`9852c038
    nop
    add     rsp,28h
    ret
    

    因此,您可能会得出结论,因为执行的是相同的机器代码,所以两种方法的性能都是相同的。

    您是如何编译代码的?它是处于调试模式还是发布模式?我相信,在这个版本中,两个IL看起来完全一样。它是在调试中编译的。让我检查一下发布模式。发布构建的结果相同。除非您的vm通过电子邮件将il发送到远程服务器执行,否则不会。我想知道,stloc/ldloc对的周期相对成本是多少?你认为它很可能被优化成一个寄存器吗?@JerKimball:很可能。但是优化JIT并不需要非常聪明就能发现这一点:)除了存在“nop”之外,我看不到调试版本和发布版本有任何区别。可以肯定的是,前一种方法的可读性更好,使用类似string.Format的更复杂的字符串形成。这就是我争论的地方,是否让一个局部变量保存字符串,然后将其传递给下面的方法。@ashtee:不需要争论,只需编写简单的代码即可。将解析格式字符串、构建新字符串等的复杂性与存储引用然后再次加载的可能工作(在JITting之后可能根本不存在)进行比较。感谢您的澄清。
        .method private hidebysig static void  DoNotCreateCopyOfString() cil managed
        {
              // Code size       13 (0xd)
              .maxstack  8
              IL_0000:  nop
              IL_0001:  ldstr      "Hello"
              IL_0006:  call       void ConsoleApplication1.Program::ProcessString(string)
              IL_000b:  nop
              IL_000c:  ret
        } // end of method Program::DoNotCreateCopyOfString
    
    sub     rsp,28h
    mov     rcx,121E3258h
    mov     rcx,qword ptr [rcx]
    call    000007fe`9852c038
    nop
    add     rsp,28h
    ret