7

私は最近、Dave Detlefs によるこの記事を読んでいました。この記事では、CLR が配列境界チェックの削除を実行するいくつかのケースを紹介しています。これを自分でテストすることにしたので、次のことを行いました。

  • Visual Studio 2010 Ultimate SP1 をオープン
  • コンソール アプリケーション タイプの新しい C# プロジェクトを作成しました (デフォルトで .NET 4 クライアント プロファイルを対象としています)。
  • 次のコードを追加しました (すべてのサブメソッドは記事から直接取得されます)。

    class Program {
        static void Main(string[] args) {
            int[] array = new int[30];
            Test_SimpleAscend(array);
            Test_SimpleRedundant(array, 3);
    
            foreach (int i in array) {
                Console.WriteLine(i);
            }
        }
    
        static void Test_SimpleAscend(int[] a) {
            for (int i = 0; i < a.Length; i++)
                a[i] = i;
        }
    
        static void Test_SimpleRedundant(int[] a, int i) {
            int k = a[i];
            k = k + a[i];
        }
    }
    
  • リリースモードに切り替えました。ビルドオプションで「コードの最適化」がチェックされていることを確認しました

  • 各配列アクセスにブレークポイントを追加し、デバッグを開始 (F5) し、逆アセンブリ ウィンドウを開きました

a[i] = i; の分解は次のとおりです。Test_SimpleAscend で:

                a[i] = i;
00000024  mov         eax,dword ptr [ebp-4] 
00000027  mov         edx,dword ptr [ebp-8] 
0000002a  cmp         eax,dword ptr [edx+4] 
0000002d  jb          00000034 
0000002f  call        64FD6E08 
00000034  mov         ecx,dword ptr [ebp-4] 
00000037  mov         dword ptr [edx+eax*4+8],ecx 

cmp/jb/call は境界チェックです。実際に呼び出しを強制的に実行すると、IndexOutOfRangeException がスローされます。

Test_SimpleRedundant の冗長アクセスを含む、すべての配列アクセスについて同じことが言えます。私のテスト方法論に何か問題がありますか、それとも CLR は境界チェックを実際に排除していませんか? 私が間違っていることを願っています。そうであれば、配列の境界チェックの削除を実際に取得する方法を知りたいです。

4

1 に答える 1

13

Cody Gray のコメントのおかげで、自分の質問に答えることができました。

デフォルトでは、デバッグ時に JIT 最適化は無効になっています。これを修正するには、[デバッグ] -> [オプションと設定] -> [デバッグ] -> [全般] に移動し、[マイ コードのみを有効にする] と [モジュールの読み込み時に JIT 最適化を抑制する] の両方のチェックを外します。

https://docs.microsoft.com/en-us/visualstudio/debugger/jit-optimization-and-debuggingも参照してください。

最適化を有効にすると、宣伝どおりに境界チェックが削除されます。

これは、ドキュメントの目的でここに残します。

于 2012-02-16T02:56:23.577 に答える