簡體   English   中英

C#:Deconstruct(…) 是否會在編譯的 output 中生成額外的垃圾分配?

[英]C#: Does Deconstruct(…) generate extra junk assignments in the compiled output?

我正在檢查解構是否會導致在堆上實例化額外的對象,因為我在需要盡可能少的 GC 壓力的區域做某事。 這是我正在嘗試的代碼:

using System;

public struct Pair
{
    public int A;
    public int B;

    public Pair(int a, int b) 
    {
        A = a;
        B = b;
    }

    public void Deconstruct(out int a, out int b)
    {
        a = A;
        b = B;
    }
}

public class Program
{
    public static void Main()
    {
        Pair pair = new Pair(1, 2);

        // Line of interest
        (int a, int b) = pair;

        Console.WriteLine(a + " " + b);
    }
}

我通過SharpLab運行了這個,看看 C# 為我做了什么,它做了以下事情:

public static void Main()
{
    Pair pair = new Pair(1, 2);
    Pair pair2 = pair;
    int a;
    int b;
    pair2.Deconstruct(out a, out b);
    int num = a;
    int num2 = b;
    Console.WriteLine(num.ToString() + " " + num2.ToString());
}

這回答了我最初的問題,即我是否必須擔心額外的分配......但更有趣的是,發布模式(因為上面是調試)有:

public static void Main()
{
    int a;
    int b;
    new Pair(1, 2).Deconstruct(out a, out b);
    int num = a;
    int num2 = b;
    Console.WriteLine(num.ToString() + " " + num2.ToString());
}

然而,這可以減少到(這是我做一些額外的變量修剪numnum2 ):

public static void Main()
{
    int a;
    int b;
    new Pair(1, 2).Deconstruct(out a, out b);
    Console.WriteLine(a.ToString() + " " + b.ToString());
}

這是一個有趣的問題,因為兩個整數的額外堆棧分配對我的程序性能沒有任何意義。 雖然我嘗試查看Main的 IL 並得到:

// Methods
.method public hidebysig static 
    void Main () cil managed 
{
    // Method begins at RVA 0x2074
    // Code size 54 (0x36)
    .maxstack 3
    .locals init (
        [0] int32,
        [1] int32,
        [2] valuetype Pair,
        [3] int32,
        [4] int32
    )

    IL_0000: ldc.i4.1
    IL_0001: ldc.i4.2
    IL_0002: newobj instance void Pair::.ctor(int32, int32)
    IL_0007: stloc.2
    IL_0008: ldloca.s 2
    IL_000a: ldloca.s 3
    IL_000c: ldloca.s 4
    IL_000e: call instance void Pair::Deconstruct(int32&, int32&)
    IL_0013: ldloc.3
    IL_0014: stloc.0
    IL_0015: ldloc.s 4
    IL_0017: stloc.1
    IL_0018: ldloca.s 0
    IL_001a: call instance string [System.Private.CoreLib]System.Int32::ToString()
    IL_001f: ldstr " "
    IL_0024: ldloca.s 1
    IL_0026: call instance string [System.Private.CoreLib]System.Int32::ToString()
    IL_002b: call string [System.Private.CoreLib]System.String::Concat(string, string, string)
    IL_0030: call void [System.Console]System.Console::WriteLine(string)
    IL_0035: ret
} // end of method Program::Main

JIT ASM 是

Program.Main()
    L0000: push ebp
    L0001: mov ebp, esp
    L0003: push edi
    L0004: push esi
    L0005: push ebx
    L0006: sub esp, 0x20
    L0009: lea edi, [ebp-0x28]
    L000c: call 0x68233ac
    L0011: mov eax, ebp
    L0013: mov [ebp-0x14], eax
    L0016: push 0x3
    L0018: mov dword [ebp-0x20], 0x6cce29c
    L001f: mov eax, esp
    L0021: mov [ebp-0x1c], eax
    L0024: lea eax, [0x146004df]
    L002a: mov [ebp-0x18], eax
    L002d: mov byte [esi+0x8], 0x0
    L0031: call dword [0x6cce680]
    L0037: mov byte [esi+0x8], 0x1
    L003b: cmp dword [0x621e5188], 0x0
    L0042: jz L0049
    L0044: call 0x62023890
    L0049: xor eax, eax
    L004b: mov [ebp-0x18], eax
    L004e: mov byte [esi+0x8], 0x1
    L0052: mov eax, [ebp-0x24]
    L0055: mov [esi+0xc], eax
    L0058: lea esp, [ebp-0xc]
    L005b: pop ebx
    L005c: pop esi
    L005d: pop edi
    L005e: pop ebp
    L005f: ret

但是,當涉及到裝配部分時,我有點不合群。

如前所述,那里有任何中間體嗎? 我感興趣的是

int num = a;
int num2 = b;

是否完全優化。 我也對為什么編譯器會在發布版本中創建中間體(有原因嗎?)或者它是否是 SharpLab 的反編譯工件感興趣。

這適用於 GC 暫停很糟糕的游戲引擎。

由於 GC 暫停的成本很重要,因此非常清楚:您正在執行實時編程 而且我只能說Realtime Programming和GC Memory Management不要混用。

你也許可以解決這個問題,但還會有另一個問題。 然后是另一個。 然后越來越多,直到你終於意識到自己走上了死胡同。 您越早意識到自己可能處於死胡同,您就能挽救的工作就越多。

從歷史上看,游戲引擎——尤其是繪圖代碼——是使用直接 memory 管理的非托管代碼。 .NET 代碼與位數無關。 但是一旦你使用了專業的繪圖代碼,你基本上就被它的位數束縛住了。 但是我無法判斷這是否只是慣性(我們之前使用過該引擎並且不會更改它,只是因為語言/運行時做了)還是它對性能很重要。

我也不能說有多少 Unity 繪圖代碼使用了非托管代碼。 但由於需要為特定平台構建 Unity 游戲,我將假設:多於沒有。 所以很可能在做游戲引擎時不進入非托管代碼是不可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM