C# では構造体パラメーターを使用して関数をインライン化しないのはなぜですか?

StackOverflow https://stackoverflow.com/questions/1049564

  •  20-08-2019
  •  | 
  •  

質問

http://blogs.msdn.com/ericgu/archive/2004/01/29/64717.aspx, で、C# は構造体を仮パラメータとして持つメソッドをインライン化しないことがわかります。これはスタックへの潜在的な依存によるものですか。再帰のためですか?もしそうなら、このように構造体パラメータを参照パラメータに変換することで利益が得られる可能性はありますか?

public int Sum(int i)
{
  return array1[i] + array2[i];
}

になる:

public int Sum(ref int i)
{
  return array1[i] + array2[i];
}

編集:テストを試みましたが、インラインでは何も取得できません。私が試したことは次のとおりです。

class Program
{
  private static string result;
  static void Main(string[] args)
  {
    Console.WriteLine(MethodBase.GetCurrentMethod().Name);
    Console.WriteLine();
    m1();
    Console.WriteLine(result);
  }
  private static void m1()
  {
    result = MethodBase.GetCurrentMethod().Name;
  }
}

2 行目に「m1」が出力されます。これは、インライン化されなかったことを示します。リリース ビルドをビルドし、Ctrl-F5 キーを押して実行しました (デバッガーを接続しないため)。何か案は?

役に立ちましたか?

解決

ジョンが言ったように、それは非常に古いポストです。私は、次のコードでそれを確認することができます:

using System;
using System.Runtime.CompilerServices;

struct MyStruct
{
   public MyStruct(int p)
   {
      X = p;
   }
   public int X;

   // prevents optimization of the whole thing to a constant.
   [MethodImpl(MethodImplOptions.NoInlining)]
   static int GetSomeNumber()
   {
       return new Random().Next();
   }

   static void Main(string[] args)
   {
      MyStruct x = new MyStruct(GetSomeNumber());
      // the following line is to prevent further optimization:
      for (int i = inlinetest(x); i != 100 ; i /= 2) ; 
   }

   static int inlinetest(MyStruct x)
   {
      return x.X + 1;
   }
}

inlinetestメソッドがインライン化されている。

Mainメソッドの解体ます:

; set up the stack frame:
00000000  push        ebp
00000001  mov         ebp,esp 

; calls GetSomeNumber:
00000003  call        dword ptr ds:[005132D8h] 

; inlined function:
00000009  inc         eax  

; the dummy for loop:
0000000a  cmp         eax,64h 
0000000d  je          0000001B 
0000000f  sar         eax,1 
00000011  jns         00000016 
00000013  adc         eax,0 
00000016  cmp         eax,64h 
00000019  jne         0000000F 
0000001b  pop         ebp  
0000001c  ret 

私は、Windows 7のx64 RC上のx86の.NET Framework 3.5 SP1でこれをテストしてみます。

私はstructパラメータを持つインライン化の方法と本質的に間違って何もないと信じたよう。おそらく、JITは、その時点で十分にスマートされていません。

他のヒント

<のhref = "http://blogs.msdn.com/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx" rel =「nofollowをnoreferrer」>いくつかのメソッドがインライン化されない理由について説明する。ここの「SAより良い記事。そして、ここをMSには、コメントとフィードバック入力を接続していますベンチマーク結果(FWIW)

明確化のビット。そのブログは、C#がまたはインラインませんなるか議論されていません。 JITerがたりないでしょうインライン化するかを検討しています。

JITerは、仮パラメータとして構造体とのインラインメソッドをしない理由として、私は知らない。
しかし、私は、彼らが構造体のパラメータを持つメソッドをインライン化しません場合は、REFによって構造体を作ることはその決定を変更しないということは比較的一定しています。

これはそのメソッド用に作成されたスタックフレームのサイズを変更する伴うだろうので、

私の最初の推測ではあります。参照型(クラス)とフレーム構造体とのすべての構造体プリミティブフィールドに対し、(ヒープ上のオブジェクトへの)ポインタの格納を可能にするために有しているスタックはStackFrameをフットプリントに追加されなければなりません。

これは 値型と参照型の問題, 、あなたが指摘したように。値型 (たとえば、int) の引数を持つ関数があると想像してください。 関数内のその変数を変更します. 。明らかに、これは 呼び出し関数に副作用はありません, 、参照ではなく値によって渡されたためです。

次に、同じコードをインライン化すると想像してください。突然、 呼び出し元の関数で変数が変更されています!意図したものではありません。

おそらく、次の参照型を使用して同じシナリオを考えてみると納得できるでしょう。 インライン化では by-ref パラメータに問題はありません - 元の関数の変更は、その関数のインライン化バージョンの変更と同じ影響を及ぼします。

それがそれを許可しない理由ですが、関数が値型の引数に副作用がないことをコンパイラに「保証」するように伝える何らかの方法があるべきであるという点には同意します。多くの場合、パフォーマンス上の理由からこれが適している可能性があります。

ちなみに、いつでもモジュール レベルの int を宣言して、引数をまとめてバイパスすることができます :) はるかに醜いですが、問題の関数をインライン化することになります。

何をするにしても、頑張ってください!

編集:Irix (SGI オペレーティング システム) には古い C コンパイラがあり、実際にインライン化を「強制」できるコンパイラ オプションがあったことを思い出しました。したがって、それを実行することは可能ですが、私はここでの選択に同意し、エラーが発生しにくいデフォルトを選択します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top