C# では構造体パラメーターを使用して関数をインライン化しないのはなぜですか?
-
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 コンパイラがあり、実際にインライン化を「強制」できるコンパイラ オプションがあったことを思い出しました。したがって、それを実行することは可能ですが、私はここでの選択に同意し、エラーが発生しにくいデフォルトを選択します。