简体   繁体   English

C#集合初始化语法是否避免默认初始化开销

[英]Does C# Collection Initialization Syntax Avoid Default Initialization Overhead

When you use the new C# collection initialization syntax: 使用新的C#集合初始化语法时:

string[] sarray = new[] { "A", "B", "C", "D" };

does the compiler avoid initializing each array slot to the default value, or is it equivalent to: 编译器是否避免将每个数组槽初始化为默认值,或者它是否等效于:

string[] sarray = new string[4];  // all slots initialized to null
sarray[0] = "A";
sarray[1] = "B";
sarray[2] = "C";
sarray[3] = "D";

The compiler still uses the newarr IL instruction, so the CLR will still initialize the array. 编译器仍然使用newarr IL指令,因此CLR仍将初始化数组。

Collection initialization is just compiler magic - the CLR doesn't know anything about it, so it'll still assume it has to do sanity clearance. 集合初始化只是编译器的魔力 - CLR对它一无所知,所以它仍然认为它必须做清理。

However, this should be really, really quick - it's just wiping memory. 但是,这应该非常非常快 - 它只是擦拭内存。 I doubt it's a significant overhead in many situations. 我怀疑在许多情况下这是一个重大的开销。

Quick test: 快速测试:

        string[] arr1 =
        {
            "A","B","C","D"
        };
        arr1.GetHashCode();

        string[] arr2 = new string[4];
        arr2[0] = "A";
        arr2[1] = "B";
        arr2[2] = "C";
        arr2[3] = "D";

        arr2.GetHashCode();

results in this IL (note, they're both identical) 结果在这个IL(注意,它们都是相同的)

  IL_0002:  newarr     [mscorlib]System.String
  IL_0007:  stloc.2
  IL_0008:  ldloc.2
  IL_0009:  ldc.i4.0
  IL_000a:  ldstr      "A"
  IL_000f:  stelem.ref
  IL_0010:  ldloc.2
  IL_0011:  ldc.i4.1
  IL_0012:  ldstr      "B"
  IL_0017:  stelem.ref
  IL_0018:  ldloc.2
  IL_0019:  ldc.i4.2
  IL_001a:  ldstr      "C"
  IL_001f:  stelem.ref
  IL_0020:  ldloc.2
  IL_0021:  ldc.i4.3
  IL_0022:  ldstr      "D"
  IL_0027:  stelem.ref
  IL_0028:  ldloc.2
  IL_0029:  stloc.0
  IL_002a:  ldloc.0
  IL_002b:  callvirt   instance int32 [mscorlib]System.Object::GetHashCode()
  IL_0030:  pop
  IL_0031:  ldc.i4.4
  IL_0032:  newarr     [mscorlib]System.String
  IL_0037:  stloc.1
  IL_0038:  ldloc.1
  IL_0039:  ldc.i4.0
  IL_003a:  ldstr      "A"
  IL_003f:  stelem.ref
  IL_0040:  ldloc.1
  IL_0041:  ldc.i4.1
  IL_0042:  ldstr      "B"
  IL_0047:  stelem.ref
  IL_0048:  ldloc.1
  IL_0049:  ldc.i4.2
  IL_004a:  ldstr      "C"
  IL_004f:  stelem.ref
  IL_0050:  ldloc.1
  IL_0051:  ldc.i4.3
  IL_0052:  ldstr      "D"
  IL_0057:  stelem.ref
  IL_0058:  ldloc.1
  IL_0059:  callvirt   instance int32 [mscorlib]System.Object::GetHashCode()

I ran a short test on instantianting an array using the syntax you describe and found that instantiating with non-default values took about 2.2 fold longer than instantiantion with default values. 我使用您描述的语法对实例化数组进行了一个简短的测试,发现使用非默认值实例化的时间比使用默认值的实例长约2.2倍。

When I switched and instantiated with default values, it takes about the same amount of time. 当我使用默认值切换和实例化时,它需要大约相同的时间。

Indeed, when I looked at the decompile it appears that what happens is the array is initialized, and then is populated with any values that are not the default. 实际上,当我查看反编译时,似乎发生了什么是数组被初始化,然后填充了任何非默认值。

Instantiating with non default values: 使用非默认值进行实例化:

            bool[] abPrimes = new[] { 
                true, true
            };
0000007e  mov         edx,2 
00000083  mov         ecx,79114A46h 
00000088  call        FD3006F0 
0000008d  mov         dword ptr [ebp-64h],eax 
00000090  mov         eax,dword ptr [ebp-64h] 
00000093  mov         dword ptr [ebp-54h],eax 
00000096  mov         eax,dword ptr [ebp-54h] 
00000099  cmp         dword ptr [eax+4],0 
0000009d  ja          000000A4 
0000009f  call        76A9A8DC 
000000a4  mov         byte ptr [eax+8],1 
000000a8  mov         eax,dword ptr [ebp-54h] 
000000ab  cmp         dword ptr [eax+4],1 
000000af  ja          000000B6 
000000b1  call        76A9A8DC 
000000b6  mov         byte ptr [eax+9],1 
000000ba  mov         eax,dword ptr [ebp-54h] 
000000bd  mov         dword ptr [ebp-40h],eax 

Instantiating with default values: 使用默认值进行实例化:

bool[] abPrimes2 = new[] { 
              false, false
            };
000000c0  mov         edx,2 
000000c5  mov         ecx,79114A46h 
000000ca  call        FD3006F0 
000000cf  mov         dword ptr [ebp-68h],eax 
000000d2  mov         eax,dword ptr [ebp-68h] 
000000d5  mov         dword ptr [ebp-54h],eax 
000000d8  mov         eax,dword ptr [ebp-54h] 
000000db  mov         dword ptr [ebp-5Ch],eax 

It is not possible to avoid initializing each array slot to the default value, at least in IL level. 不可能避免将每个阵列槽初始化为默认值,至少在IL级别。

String is a CLASS, not a struct. String是CLASS,而不是struct。

That means A, B, C, D and the sarray could be stored in any position. 这意味着A,B,C,D和sarray可以存储在任何位置。 A, B, C and D might be get from the Intern pool, that the reference to the object could be dynamic. A,B,C和D可能来自Intern池,对象的引用可能是动态的。

But I believe that the JIT could smart enough to reduce half of these overhead. 但我相信JIT可以足够聪明地减少一半的开销。

PS. PS。 Premature optimization being the root of all evil. 过早优化是万恶之源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM