インライン関数を使用すると、メモリ使用量は増加しますか?
8 に答える
インライン関数が影響するメモリ使用量には、次の 2 種類があります。
コード サイズ— 一般に、コードをインライン展開すると、プログラムの読み込みに使用されるメモリの量が増加します。これは、生成されたコードの複数のコピーがプログラム中に散在するためです。ただし、これは常に正しいとは限りません。インライン化された関数が 1 回しか使用されていない場合、変更はほとんどありません。また、インライン化された関数が非常に小さい場合は、関数呼び出しのオーバーヘッドを取り除くことで、コード サイズを実質的に削減できます。また、関数は、特定のインライン呼び出しで使用されていないコードを削除できるオプティマイザーによってサイズが縮小される場合があります。
スタックの使用— インライン化された関数に多数のローカル変数がある場合は、より多くのスタック スペースを使用できます。C では、コンパイラは通常、関数へのエントリ時に関数のスタック領域を 1 回割り当てます。これは、レジスタに格納されていないすべてのローカル変数を保持するのに十分な大きさである必要があります。関数をアウト オブ ラインで呼び出すと、その関数のスタックは、再び解放されたときに戻るまで使用されます。関数をインライン化すると、そのスタック スペースは、uber-function の全期間にわたって使用されたままになります。
インライン化は、インライン化されていないバージョンで発生するのと同じ割り当てと解放がインライン化されたコードで発生するため、ヒープの使用には影響しません。
考慮しなければならない別の点があります。
インライン関数を使用すると、コンパイラは、呼び出し元の変数が呼び出し先の変数として使用される場所を確認できます。コンパイラーは、その知識に基づいて冗長コードを最適化できます (多くの場合、これは省略できるアセンブラーの行が非常に多いためです。いわゆる「エイリアシングの問題」に注意してください)。したがって、「コードの肥大化」はそれほど大きくないことが多く、特に関数が小さい場合は、ジムが上で述べたように肥大化を減らすことさえできます.
誰かが良い点を指摘しました。問題の関数をインライン化するかどうかをコンパイラーに決定させた方がよいでしょう。
機能によって異なります。単純なワンライナーでは、コールスタックを設定してクリーンアップする必要がなく、関数呼び出しも行われないため、メモリを削減できます。関数が関数を呼び出すために必要なこのオーバーヘッドよりも大きい場合は、もちろんコードが肥大化します。
それは一般的なケースでは本当に答えられません。
まず、一般的にインラインを制御することはできません。関数をインラインとしてマークしても、実際にはコンパイラ次第であり、実際にはインライン化を行います (これは単なるヒントです)。
コンパイラはコードを最適化するために最善を尽くします。インライン化の使用は、これを行うための 1 つのツールにすぎません。したがって、短い関数をインライン化すると、コードが小さくなります (呼び出しのパラメーターを設定したり、戻り値を取得したりする必要がないためです。ただし、長い関数を使用しても、答えは絶対ではありません。
コンパイラが長い関数をインライン化することを決定した場合、コードが長くなると思うでしょう。しかし、これは一般的には当てはまりません。これにより、コンパイラは、コードをさらに小さくする可能性のある他の最適化手法を適用する機会が増えるためです。コンパイラの分析により、結果として生じるコードの肥大化がコードにとって有害であることが判明した場合、インライン化は行われません。
基本的に、コンパイラは分析を行い、最善の行動方針を決定します。
結論。ご心配なく。コンパイラはあなたより賢く、正しいことをします。
インライン関数は、呼び出す場所に「コピー貼り付け」されるため、最終的な実行可能ファイル(またはバイナリ)のサイズを確実に大きくします。
一般的に、プログラムは大きくなります (ただし、例外もあると思います)。実行時のメモリ消費量は減少する可能性がありますが、それほどではありません。
なぜ質問するのですか?通常、関数をインライン化するかどうかはコンパイラーに決定させます。関数のサイズと複雑さを考えると、通常はより適切な呼び出しを行うことができます。
関数呼び出しには、いくつかのプロセッサ命令が必要です。
通常、関数の引数ごとに PUSH 命令、関数を呼び出す CALL 命令、および多くの場合、関数呼び出し後にスタックをクリーンアップする別の命令が必要です。
また、関数はプロセッサのレジスタを変更する可能性があるため、呼び出し元の関数は、レジスタを保持したり、レジスタに残っている値をリロードしたりするために、より多くの命令を必要とする場合があります。
したがって、呼び出している関数がほんの数命令の長さである場合、インライン化するとメモリが節約され、実行が速くなります。
そうは言っても、インライン化は、プロファイラーがそうすべきだと言ったときのためのものです。
プログラム全体に関数が散らばっている場合があります。この場合、関数呼び出しにより、プログラムは関数のアドレスにジャンプし、関数呼び出しが終了すると戻ってきます。これにより、貴重な時間が奪われます。
上記の問題は、インライン関数を使用して解決できます。これにより、コンパイラはソースから直接コードを呼び出します。インライン関数コード用の新しいメモリ命令セットは作成されません。
C++ のインライン宣言は自由で、関数が宣言で定義されると自動的に発生しますが、c では次の規則によって制限されます::
C では、内部リンケージを持つすべての関数をインラインで宣言できますが、外部リンケージを持つ関数にはインラインでの制限があります。
関数宣言で inline キーワードが使用されている場合、関数定義は同じ翻訳単位に存在する必要があります。
インラインデータ型 function_name(arguments)
このコードは、非インライン関数よりも最大 30% 速く実行されますが、残りはプロセッサの速度に依存します。
今度は戦略の部分です。インライン関数を自由に使用できますが、インライン関数は実行にかかる時間が大幅に短縮されますが、実行中のメモリ占有率が高いことに注意してください。また、コンパイラには、インラインで宣言されたコードがコード サイズに比べて異常に大きい場合に、インライン宣言を見落とすオプションが常にあります。
インライン宣言は評価の順序を破壊しますが、関数を内部にはしません。関数はまだ外部です。