2009-06-18 20 views

答えて

13

コンパイラは引き続きnewarr IL命令を使用するため、CLRは引き続き配列を初期化します。

コレクション初期化ちょうどコンパイラマジック - CLRはそれについて何も知らないので、まだそれは正気のクリアランスを行う必要があると仮定します。

しかし、これは本当にすばやくすべきです。メモリを拭くだけです。私はそれが多くの状況で重大なオーバーヘッドだとは思わない。

+0

興味深い。配列の初期化に対するこの「メモリワイプ」アプローチが、構造体が明示的なデフォルトコンストラクタまたはメンバ初期化子をサポートしていない理由の1つであるかどうかは疑問です。配列の初期化が複雑になります。 – LBushkin

+1

はい、そうです。実際、IL *の構造体は、パラメータのないコンストラクタをサポートしていますが、特定の状況でのみ呼び出されます。 –

+0

詳細についてはhttp://msmvps.com/blogs/jon_skeet/archive/2008/12/10/value-types-and-parameterless-constructors.aspxを参照してください。 –

10

クイックテスト:このILで

 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(); 

結果(ノート、彼らは同じ両方です)

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() 
+0

+1テスト用です。 –

1

私はあなたが記述構文を使用して配列をinstantiantingに短いテストを実行していデフォルト以外の値でインスタンス化すると、デフォルト値でインスタンス化するより約2.2倍長くなりました。

デフォルト値で切り替えてインスタンス化すると、ほぼ同じ時間がかかります。

実際、デコンパイルを見ると、配列は初期化され、デフォルト以外の値が設定されているように見えます。

非デフォルト値でインスタンス化:

  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 

はデフォルト値でインスタンス化:

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 
0

、少なくともILレベルでは、デフォルト値に各アレイのスロットを初期化回避することは不可能です。

文字列は構造体ではなくCLASSです。

これは、A、B、C、Dおよび任意の位置に格納できることを意味します。 A、B、C、DはInternプールから取得でき、オブジェクトへの参照は動的である可能性があります。

しかし、私はJITがこれらのオーバーヘッドの半分を減らすのに十分にスマートになると信じています。

PS。早期最適化はすべての悪の根源です。